diff --git a/.astyleignore b/.astyleignore index a785025..3056894 100644 --- a/.astyleignore +++ b/.astyleignore @@ -1,11 +1,11 @@ ^BUILD ^cmsis -^components/TARGET_PSA/services/attestation/attestation.h -^components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl -^components/TARGET_PSA/services/attestation/qcbor -^components/TARGET_PSA/services/crypto/COMPONENT_PSA_SRV_IPC/crypto_struct_ipc.h -^components/TARGET_PSA/TARGET_TFM -^components/TARGET_PSA/TESTS +^components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/attestation.h +^components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl +^components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/qcbor +^components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/crypto/COMPONENT_PSA_SRV_IPC/crypto_struct_ipc.h +^components/TARGET_PSA/TARGET_MBED_PSA_SRV/TARGET_TFM +^components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS ^features/cryptocell ^features/FEATURE_BLE ^features/frameworks diff --git a/LICENSE.md b/LICENSE.md index 831caa1..6c226be 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -6,7 +6,7 @@ - [cmsis](./cmsis) - MIT, BSD-3-Clause - [components/802.15.4_RF/mcr20a-rf-driver](./components/802.15.4_RF/mcr20a-rf-driver) - BSD-3-Clause - [components/TARGET_PSA/TARGET_TFM](./components/TARGET_PSA/TARGET_TFM) - BSD-3-Clause -- [components/TARGET_PSA/TARGET_PSA/services/attestation](./components/TARGET_PSA/services/attestation) - BSD-3-Clause +- [components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation](./components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation) - BSD-3-Clause - [features/cryptocell/FEATURE_CRYPTOCELL310](./features/cryptocell/FEATURE_CRYPTOCELL310) - ARM Object Code and Header Files License - [features/FEATURE_BOOTLOADER](./features/FEATURE_BOOTLOADER) - PBL - [features/FEATURE_BLE/targets](./features/FEATURE_BLE/targets) - BSD-style, PBL, MIT-style diff --git a/TESTS/psa/attestation/main.cpp b/TESTS/psa/attestation/main.cpp deleted file mode 100755 index c7305ca..0000000 --- a/TESTS/psa/attestation/main.cpp +++ /dev/null @@ -1,164 +0,0 @@ -/* -* Copyright (c) 2019 ARM Limited. All rights reserved. -* -* SPDX-License-Identifier: Apache-2.0 -* -* Licensed under the Apache License, Version 2.0 (the License); you may -* not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an AS IS BASIS, WITHOUT -* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#if !defined(MBED_CONF_RTOS_PRESENT) -#error [NOT_SUPPORTED] PSA attestation test cases require RTOS to run. -#else - -#include "psa/crypto.h" - -#if ((!defined(TARGET_PSA)) || (!defined(MBEDTLS_PSA_CRYPTO_C))) -#error [NOT_SUPPORTED] Mbed Crypto is OFF - skipping. -#else - -#include "greentea-client/test_env.h" -#include "unity/unity.h" -#include "utest/utest.h" -#include "psa/lifecycle.h" -#include "psa_initial_attestation_api.h" -#include "psa_attest_inject_key.h" -#include -#include - -#include "entropy.h" -#include "entropy_poll.h" - -/* MAX value support macro */ -#if !defined(MAX) -#define MAX(a,b) (((a)>(b))?(a):(b)) -#endif - -#define MBEDTLS_PSA_INJECT_ENTROPY_MIN_SIZE \ -MAX(MBEDTLS_ENTROPY_MIN_PLATFORM, MBEDTLS_ENTROPY_BLOCK_SIZE) - -using namespace utest::v1; - -utest::v1::status_t greentea_test_setup(const size_t number_of_cases) -{ - GREENTEA_SETUP(60, "default_auto"); - return greentea_test_setup_handler(number_of_cases); -} - -#define PSA_ATTESTATION_PRIVATE_KEY_ID 17 - -static const uint8_t private_key_data[] = { - 0x49, 0xc9, 0xa8, 0xc1, 0x8c, 0x4b, 0x88, 0x56, - 0x38, 0xc4, 0x31, 0xcf, 0x1d, 0xf1, 0xc9, 0x94, - 0x13, 0x16, 0x09, 0xb5, 0x80, 0xd4, 0xfd, 0x43, - 0xa0, 0xca, 0xb1, 0x7d, 0xb2, 0xf1, 0x3e, 0xee -}; - -static const uint8_t public_key_data[] = { - 0x04, 0x77, 0x72, 0x65, 0x6f, 0x81, 0x4b, 0x39, - 0x92, 0x79, 0xd5, 0xe1, 0xf1, 0x78, 0x1f, 0xac, - 0x6f, 0x09, 0x9a, 0x3c, 0x5c, 0xa1, 0xb0, 0xe3, - 0x53, 0x51, 0x83, 0x4b, 0x08, 0xb6, 0x5e, 0x0b, - 0x57, 0x25, 0x90, 0xcd, 0xaf, 0x8f, 0x76, 0x93, - 0x61, 0xbc, 0xf3, 0x4a, 0xcf, 0xc1, 0x1e, 0x5e, - 0x07, 0x4e, 0x84, 0x26, 0xbd, 0xde, 0x04, 0xbe, - 0x6e, 0x65, 0x39, 0x45, 0x44, 0x96, 0x17, 0xde, - 0x45 -}; - -#define TEST_TOKEN_SIZE (0x200) -#define TEST_CHALLENGE_OBJ_SIZE (32u) - -#define CHALLENGE_FOR_TEST 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, \ - 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, \ - 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, \ - 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF - -static uint8_t token_buffer[TEST_TOKEN_SIZE]; -static uint8_t challenge_buffer[TEST_CHALLENGE_OBJ_SIZE] = {CHALLENGE_FOR_TEST}; - -static void check_initial_attestation_get_token() -{ - psa_status_t status = PSA_SUCCESS; - size_t exported_length; - uint8_t exported[sizeof(public_key_data)]; - enum psa_attest_err_t attest_err = PSA_ATTEST_ERR_SUCCESS; - uint32_t token_size; - - status = psa_crypto_init(); - TEST_ASSERT_EQUAL(PSA_SUCCESS, status); - status = psa_attestation_inject_key(private_key_data, - sizeof(private_key_data), - PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_CURVE_SECP_R1), - exported, - sizeof(exported), - &exported_length); - - TEST_ASSERT_EQUAL(PSA_SUCCESS, status); - TEST_ASSERT_EQUAL(sizeof(public_key_data), exported_length); - TEST_ASSERT_EQUAL(0, memcmp(public_key_data, exported, exported_length)); - - attest_err = psa_initial_attest_get_token_size(TEST_CHALLENGE_OBJ_SIZE, - &token_size); - - TEST_ASSERT_EQUAL(PSA_ATTEST_ERR_SUCCESS, attest_err); - - attest_err = psa_initial_attest_get_token(challenge_buffer, - TEST_CHALLENGE_OBJ_SIZE, - token_buffer, - &token_size); - - TEST_ASSERT_EQUAL(PSA_ATTEST_ERR_SUCCESS, attest_err); -} -/***************************************************************************************/ - -utest::v1::status_t case_teardown_handler(const Case *const source, const size_t passed, const size_t failed, const failure_t reason) -{ - psa_key_handle_t handle; - psa_open_key(PSA_ATTESTATION_PRIVATE_KEY_ID, &handle); - psa_destroy_key(handle); - mbedtls_psa_crypto_free(); - return greentea_case_teardown_handler(source, passed, failed, reason); -} - -utest::v1::status_t case_setup_handler(const Case *const source, const size_t index_of_case) -{ - psa_status_t status; - status = mbed_psa_reboot_and_request_new_security_state(PSA_LIFECYCLE_ASSEMBLY_AND_TEST); - TEST_ASSERT_EQUAL(PSA_SUCCESS, status); -#if (defined(COMPONENT_PSA_SRV_IPC) || defined(MBEDTLS_ENTROPY_NV_SEED)) - uint8_t seed[MBEDTLS_PSA_INJECT_ENTROPY_MIN_SIZE] = {0}; - /* inject some seed for test*/ - for (int i = 0; i < MBEDTLS_PSA_INJECT_ENTROPY_MIN_SIZE; ++i) { - seed[i] = i; - } - - /* don't really care if this succeeds this is just to make crypto init pass*/ - mbedtls_psa_inject_entropy(seed, MBEDTLS_PSA_INJECT_ENTROPY_MIN_SIZE); -#endif - return greentea_case_setup_handler(source, index_of_case); -} - - -Case cases[] = { - Case("PSA attestation get token", case_setup_handler, check_initial_attestation_get_token, case_teardown_handler), -}; - -Specification specification(greentea_test_setup, cases); - -int main() -{ - return !Harness::run(specification); -} - -#endif // ((!defined(TARGET_PSA)) || (!defined(MBEDTLS_PSA_CRYPTO_C))) -#endif // !defined(MBED_CONF_RTOS_PRESENT) diff --git a/TESTS/psa/crypto_init/main.cpp b/TESTS/psa/crypto_init/main.cpp deleted file mode 100644 index c585449..0000000 --- a/TESTS/psa/crypto_init/main.cpp +++ /dev/null @@ -1,116 +0,0 @@ -/* -* Copyright (c) 2018 ARM Limited. All rights reserved. -* -* SPDX-License-Identifier: Apache-2.0 -* -* Licensed under the Apache License, Version 2.0 (the License); you may -* not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an AS IS BASIS, WITHOUT -* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#include "psa/crypto.h" - -#if ((!defined(TARGET_PSA)) || (!defined(MBEDTLS_PSA_CRYPTO_C))) -#error [NOT_SUPPORTED] Mbed Crypto is OFF - skipping. -#else - -#include "greentea-client/test_env.h" -#include "unity/unity.h" -#include "utest/utest.h" -#include "entropy.h" -#include "entropy_poll.h" - -#define TEST_RANDOM_SIZE 64 - -#if !defined(MAX) -#define MAX(a,b) (((a)>(b))?(a):(b)) -#endif - -/* Calculating the minimum allowed entropy size in bytes */ -#define MBEDTLS_PSA_INJECT_ENTROPY_MIN_SIZE \ - MAX(MBEDTLS_ENTROPY_MIN_PLATFORM, MBEDTLS_ENTROPY_BLOCK_SIZE) - -using namespace utest::v1; - -utest::v1::status_t greentea_test_setup(const size_t number_of_cases) -{ - GREENTEA_SETUP(60, "default_auto"); - return greentea_test_setup_handler(number_of_cases); -} - -static void check_multi_crypto_init_deinit() -{ -#if !defined(COMPONENT_PSA_SRV_IPC) - TEST_SKIP(); -#endif - uint8_t output[TEST_RANDOM_SIZE] = {0}; - - psa_status_t status = psa_crypto_init(); - TEST_ASSERT_EQUAL(PSA_SUCCESS, status); - - status = psa_crypto_init(); - TEST_ASSERT_EQUAL(PSA_SUCCESS, status); - - status = psa_generate_random(output, sizeof(output)); - TEST_ASSERT_NOT_EQUAL(PSA_ERROR_BAD_STATE, status); - - mbedtls_psa_crypto_free(); - status = psa_generate_random(output, sizeof(output)); - TEST_ASSERT_NOT_EQUAL(PSA_ERROR_BAD_STATE, status); - - mbedtls_psa_crypto_free(); - status = psa_generate_random(output, sizeof(output)); - TEST_ASSERT_EQUAL(PSA_ERROR_BAD_STATE, status); -} - -static void check_crypto_init_deinit() -{ - psa_status_t status; - uint8_t output[TEST_RANDOM_SIZE] = {0}; - - // Should fail as init is required first - status = psa_generate_random(output, sizeof(output)); - TEST_ASSERT_EQUAL(PSA_ERROR_BAD_STATE, status); - - status = psa_crypto_init(); - TEST_ASSERT_EQUAL(PSA_SUCCESS, status); - - status = psa_generate_random(output, sizeof(output)); - TEST_ASSERT_NOT_EQUAL(PSA_ERROR_BAD_STATE, status); - - mbedtls_psa_crypto_free(); - status = psa_generate_random(output, sizeof(output)); - TEST_ASSERT_EQUAL(PSA_ERROR_BAD_STATE, status); -} - -Case cases[] = { - Case("PSA crypto-init De-init", check_crypto_init_deinit), - Case("PSA crypto- multiple init De-init", check_multi_crypto_init_deinit), -}; - -Specification specification(greentea_test_setup, cases, greentea_test_teardown_handler); - -int main() -{ -#if (defined(COMPONENT_PSA_SRV_IPC) || defined(MBEDTLS_ENTROPY_NV_SEED)) - uint8_t seed[MBEDTLS_PSA_INJECT_ENTROPY_MIN_SIZE] = {0}; - /* inject some a seed for test*/ - for (int i = 0; i < MBEDTLS_PSA_INJECT_ENTROPY_MIN_SIZE; ++i) { - seed[i] = i; - } - - /* don't really care if this succeed this is just to make crypto init pass*/ - mbedtls_psa_inject_entropy(seed, MBEDTLS_PSA_INJECT_ENTROPY_MIN_SIZE); -#endif - return !Harness::run(specification); -} - -#endif // ((!defined(TARGET_PSA)) || (!defined(MBEDTLS_PSA_CRYPTO_C))) diff --git a/TESTS/psa/entropy_inject/main.cpp b/TESTS/psa/entropy_inject/main.cpp deleted file mode 100644 index 0098e8e..0000000 --- a/TESTS/psa/entropy_inject/main.cpp +++ /dev/null @@ -1,187 +0,0 @@ -/* -* Copyright (c) 2018 ARM Limited. All rights reserved. -* -* SPDX-License-Identifier: Apache-2.0 -* -* Licensed under the Apache License, Version 2.0 (the License); you may -* not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an AS IS BASIS, WITHOUT -* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#if ((!defined(TARGET_PSA) || (!defined(COMPONENT_PSA_SRV_IPC)) && !defined(MBEDTLS_ENTROPY_NV_SEED))) -#error [NOT_SUPPORTED] PSA entropy injection tests can run only on PSA-enabled targets. -#else - -#include "greentea-client/test_env.h" -#include "unity/unity.h" -#include "utest/utest.h" -#include "psa/internal_trusted_storage.h" -#include "psa/lifecycle.h" -#include "entropy.h" -#include "entropy_poll.h" -#include "psa/crypto.h" -#include - -/* MAX value support macro */ -#if !defined(MAX) -#define MAX(a,b) (((a)>(b))?(a):(b)) -#endif - -/* Calculating the minimum allowed entropy size in bytes */ -#define MBEDTLS_PSA_INJECT_ENTROPY_MIN_SIZE \ - MAX(MBEDTLS_ENTROPY_MIN_PLATFORM, MBEDTLS_ENTROPY_BLOCK_SIZE) - -using namespace utest::v1; - -uint8_t seed[MBEDTLS_ENTROPY_MAX_SEED_SIZE + 2] = {0}; -bool skip_tests = false; - -void validate_entropy_seed_injection(int seed_length_a, - int expected_status_a, - int seed_length_b, - int expected_status_b) -{ - psa_status_t status; - uint8_t output[32] = { 0 }; - uint8_t zeros[32] = { 0 }; - int memcmp_res = 0; - status = mbedtls_psa_inject_entropy(seed, seed_length_a); - TEST_ASSERT_EQUAL_INT(expected_status_a, status); - - status = mbedtls_psa_inject_entropy(seed, seed_length_b); - TEST_ASSERT_EQUAL_INT(expected_status_b, status); - - status = psa_crypto_init(); - TEST_ASSERT_EQUAL_INT(PSA_SUCCESS, status); - - status = psa_generate_random(output, sizeof(output)); - TEST_ASSERT_EQUAL_INT(PSA_SUCCESS, status); - - memcmp_res = memcmp(output, zeros, sizeof(output)); - TEST_ASSERT_NOT_EQUAL(0, memcmp_res); -} - -void run_entropy_inject_with_crypto_init() -{ - psa_status_t status; - status = psa_crypto_init(); - TEST_ASSERT_EQUAL_INT(PSA_ERROR_INSUFFICIENT_ENTROPY, status); - - status = mbedtls_psa_inject_entropy(seed, MBEDTLS_PSA_INJECT_ENTROPY_MIN_SIZE); - TEST_ASSERT_EQUAL_INT(PSA_SUCCESS, status); - - status = psa_crypto_init(); - TEST_ASSERT_EQUAL_INT(PSA_SUCCESS, status); - - status = mbedtls_psa_inject_entropy(seed, MBEDTLS_PSA_INJECT_ENTROPY_MIN_SIZE); - TEST_ASSERT_EQUAL_INT(PSA_ERROR_NOT_PERMITTED, status); - - mbedtls_psa_crypto_free(); - /* The seed is written by nv_seed callback functions therefore the injection will fail */ - status = mbedtls_psa_inject_entropy(seed, MBEDTLS_PSA_INJECT_ENTROPY_MIN_SIZE); - TEST_ASSERT_EQUAL_INT(PSA_ERROR_NOT_PERMITTED, status); -} - - -utest::v1::status_t greentea_test_setup(const size_t number_of_cases) -{ - GREENTEA_SETUP(60, "default_auto"); - - /* fill seed in some data */ - for (size_t i = 0; i < sizeof(seed); ++i) { - seed[i] = i; - } - - psa_status_t status = mbed_psa_reboot_and_request_new_security_state(PSA_LIFECYCLE_ASSEMBLY_AND_TEST); - TEST_ASSERT_EQUAL(PSA_SUCCESS, status); - - if (mbedtls_psa_inject_entropy(seed, MBEDTLS_ENTROPY_MAX_SEED_SIZE) == PSA_ERROR_NOT_SUPPORTED) { - skip_tests = true; - } - - return greentea_test_setup_handler(number_of_cases); -} - -static void injection_small_good() -{ - TEST_SKIP_UNLESS(!skip_tests); - validate_entropy_seed_injection( - MBEDTLS_PSA_INJECT_ENTROPY_MIN_SIZE, PSA_SUCCESS, - MBEDTLS_PSA_INJECT_ENTROPY_MIN_SIZE, PSA_ERROR_NOT_PERMITTED); -} - -static void injection_big_good() -{ - TEST_SKIP_UNLESS(!skip_tests); - validate_entropy_seed_injection( - MBEDTLS_ENTROPY_MAX_SEED_SIZE, PSA_SUCCESS, - MBEDTLS_ENTROPY_MAX_SEED_SIZE, PSA_ERROR_NOT_PERMITTED); -} - -static void injection_too_small() -{ - TEST_SKIP_UNLESS(!skip_tests); - validate_entropy_seed_injection( - (MBEDTLS_ENTROPY_MIN_PLATFORM - 1), PSA_ERROR_INVALID_ARGUMENT, - MBEDTLS_PSA_INJECT_ENTROPY_MIN_SIZE, PSA_SUCCESS); -} - -static void injection_too_big() -{ - TEST_SKIP_UNLESS(!skip_tests); - validate_entropy_seed_injection( - (MBEDTLS_ENTROPY_MAX_SEED_SIZE + 1), PSA_ERROR_INVALID_ARGUMENT, - MBEDTLS_ENTROPY_MAX_SEED_SIZE, PSA_SUCCESS); -} - -static void injection_and_init_deinit() -{ - TEST_SKIP_UNLESS(!skip_tests); - run_entropy_inject_with_crypto_init(); -} - - - -/***************************************************************************************/ - -utest::v1::status_t case_teardown_handler(const Case *const source, const size_t passed, const size_t failed, const failure_t reason) -{ - psa_status_t status; - status = mbed_psa_reboot_and_request_new_security_state(PSA_LIFECYCLE_ASSEMBLY_AND_TEST); - TEST_ASSERT_EQUAL(PSA_SUCCESS, status); - mbedtls_psa_crypto_free(); - return greentea_case_teardown_handler(source, passed, failed, reason); -} - -utest::v1::status_t case_setup_handler(const Case *const source, const size_t index_of_case) -{ - psa_status_t status; - status = mbed_psa_reboot_and_request_new_security_state(PSA_LIFECYCLE_ASSEMBLY_AND_TEST); - TEST_ASSERT_EQUAL(PSA_SUCCESS, status); - return greentea_case_setup_handler(source, index_of_case); -} - -Case cases[] = { - Case("PSA entropy injection small good", case_setup_handler, injection_small_good, case_teardown_handler), - Case("PSA entropy injection big good", case_setup_handler, injection_big_good, case_teardown_handler), - Case("PSA entropy injection too big", case_setup_handler, injection_too_big, case_teardown_handler), - Case("PSA entropy injection too small", case_setup_handler, injection_too_small, case_teardown_handler), - Case("PSA entropy injection before and after init", case_setup_handler, injection_and_init_deinit, case_teardown_handler), -}; - -Specification specification(greentea_test_setup, cases, greentea_test_teardown_handler); - -int main() -{ - return !Harness::run(specification); -} - -#endif // ((!defined(TARGET_PSA) || (!defined(COMPONENT_PSA_SRV_IPC)) && !defined(MBEDTLS_ENTROPY_NV_SEED))) diff --git a/TESTS/psa/its_ps/main.cpp b/TESTS/psa/its_ps/main.cpp deleted file mode 100644 index ee2c510..0000000 --- a/TESTS/psa/its_ps/main.cpp +++ /dev/null @@ -1,251 +0,0 @@ -/* -* Copyright (c) 2019 ARM Limited. All rights reserved. -* -* SPDX-License-Identifier: Apache-2.0 -* -* Licensed under the Apache License, Version 2.0 (the License); you may -* not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an AS IS BASIS, WITHOUT -* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#if !defined(MBED_CONF_RTOS_PRESENT) -#error [NOT_SUPPORTED] ITS/PS test cases require RTOS to run. -#else - -#ifndef TARGET_PSA -#error [NOT_SUPPORTED] ITS/PS tests can run only on PSA-enabled targets. -#else - -#include "greentea-client/test_env.h" -#include "unity/unity.h" -#include "utest/utest.h" -#include "psa/error.h" -#include "psa/storage_common.h" -#include "psa/internal_trusted_storage.h" -#include "psa/protected_storage.h" -#include "psa/lifecycle.h" -#include "KVMap.h" -#include "KVStore.h" -#include "kv_config.h" -#include "psa_storage_common_impl.h" -#include "DeviceKey.h" - -using namespace utest::v1; -using namespace mbed; - -#define TEST_BUFF_SIZE 16 -#define STR_EXPAND(tok) #tok - -typedef enum { - its, - ps -} storage_type_t; - -extern "C" psa_status_t psa_ps_reset(); - -static psa_status_t set_func(storage_type_t stype, psa_storage_uid_t uid, size_t data_length, - const void *p_data, psa_storage_create_flags_t create_flags) -{ - return (stype == its) ? - psa_its_set(uid, data_length, p_data, create_flags) : - psa_ps_set(uid, data_length, p_data, create_flags); -} - -static psa_status_t get_func(storage_type_t stype, psa_storage_uid_t uid, size_t data_offset, - size_t data_length, void *p_data, size_t *actual_length) -{ - return (stype == its) ? - psa_its_get(uid, data_offset, data_length, p_data, actual_length) : - psa_ps_get(uid, data_offset, data_length, p_data, actual_length); -} - -static psa_status_t get_info_func(storage_type_t stype, psa_storage_uid_t uid, - struct psa_storage_info_t *p_info) -{ - return (stype == its) ? - psa_its_get_info(uid, p_info) : - psa_ps_get_info(uid, p_info); -} - -static psa_status_t remove_func(storage_type_t stype, psa_storage_uid_t uid) -{ - return (stype == its) ? - psa_its_remove(uid) : - psa_ps_remove(uid); -} - - -template -void pits_ps_test() -{ - psa_status_t status = PSA_SUCCESS; - uint8_t write_buff[TEST_BUFF_SIZE] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F}; - uint8_t read_buff[TEST_BUFF_SIZE] = {0}; - size_t actual_size; - psa_storage_create_flags_t flags; - struct psa_storage_info_t info = {0, PSA_STORAGE_FLAG_WRITE_ONCE}; - memset(read_buff, 0, TEST_BUFF_SIZE); - - status = get_info_func(stype, 5, &info); - TEST_ASSERT_EQUAL(PSA_ERROR_DOES_NOT_EXIST, status); - - status = set_func(stype, 5, TEST_BUFF_SIZE, write_buff, 0); - TEST_ASSERT_EQUAL(PSA_SUCCESS, status); - - status = get_info_func(stype, 5, &info); - TEST_ASSERT_EQUAL(PSA_SUCCESS, status); - TEST_ASSERT_EQUAL(TEST_BUFF_SIZE, info.size); - TEST_ASSERT_EQUAL(0, info.flags); - - status = get_func(stype, 5, 0, TEST_BUFF_SIZE, read_buff, &actual_size); - TEST_ASSERT_EQUAL(PSA_SUCCESS, status); - TEST_ASSERT_EQUAL_MEMORY(write_buff, read_buff, TEST_BUFF_SIZE); - - memset(read_buff, 0, TEST_BUFF_SIZE); - status = get_func(stype, 5, 1, TEST_BUFF_SIZE, read_buff, &actual_size); - TEST_ASSERT_NOT_EQUAL(PSA_SUCCESS, status); - - status = get_func(stype, 5, 1, TEST_BUFF_SIZE - 1, read_buff, &actual_size); - TEST_ASSERT_EQUAL(PSA_SUCCESS, status); - TEST_ASSERT_EQUAL_MEMORY(write_buff + 1, read_buff, TEST_BUFF_SIZE - 1); - - status = remove_func(stype, 5); - TEST_ASSERT_EQUAL(PSA_SUCCESS, status); - - status = get_info_func(stype, 5, &info); - TEST_ASSERT_EQUAL(PSA_ERROR_DOES_NOT_EXIST, status); - - if (stype == its) { - return; - } - - mbed::KVMap &kv_map = mbed::KVMap::get_instance(); - mbed::KVStore *kvstore = kv_map.get_main_kv_instance(STR_EXPAND(MBED_CONF_STORAGE_DEFAULT_KV)); - uint32_t kv_get_flags; - - flags = PSA_STORAGE_FLAG_NO_REPLAY_PROTECTION; - status = set_func(stype, 6, TEST_BUFF_SIZE, write_buff, flags); - TEST_ASSERT_EQUAL(PSA_SUCCESS, status); - - status = get_info_func(stype, 6, &info); - TEST_ASSERT_EQUAL(PSA_SUCCESS, status); - TEST_ASSERT_EQUAL(flags, info.flags); - - status = psa_storage_get_info_impl(kvstore, 1, 6, &info, &kv_get_flags); - TEST_ASSERT_EQUAL(PSA_SUCCESS, status); - TEST_ASSERT_EQUAL(kv_get_flags, mbed::KVStore::REQUIRE_CONFIDENTIALITY_FLAG); - - flags = PSA_STORAGE_FLAG_NO_REPLAY_PROTECTION | PSA_STORAGE_FLAG_NO_CONFIDENTIALITY | PSA_STORAGE_FLAG_WRITE_ONCE; - status = set_func(stype, 6, TEST_BUFF_SIZE, write_buff, flags); - TEST_ASSERT_EQUAL(PSA_SUCCESS, status); - - status = get_info_func(stype, 6, &info); - TEST_ASSERT_EQUAL(PSA_SUCCESS, status); - TEST_ASSERT_EQUAL(flags, info.flags); - - status = psa_storage_get_info_impl(kvstore, 1, 6, &info, &kv_get_flags); - TEST_ASSERT_EQUAL(PSA_SUCCESS, status); - TEST_ASSERT_EQUAL(kv_get_flags, mbed::KVStore::WRITE_ONCE_FLAG); -} - -template -void pits_ps_write_once_test() -{ - psa_status_t status = PSA_SUCCESS; - uint8_t write_buff[TEST_BUFF_SIZE] = {0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00}; - uint8_t read_buff[TEST_BUFF_SIZE] = {0}; - size_t actual_size; - struct psa_storage_info_t info = {0, 0}; - - status = get_info_func(stype, 5, &info); - TEST_ASSERT_EQUAL(PSA_ERROR_DOES_NOT_EXIST, status); - - status = set_func(stype, 5, TEST_BUFF_SIZE, write_buff, PSA_STORAGE_FLAG_WRITE_ONCE); - TEST_ASSERT_EQUAL(PSA_SUCCESS, status); - - info.size = 0; - info.flags = PSA_STORAGE_FLAG_WRITE_ONCE; - status = get_info_func(stype, 5, &info); - TEST_ASSERT_EQUAL(PSA_SUCCESS, status); - TEST_ASSERT_EQUAL(TEST_BUFF_SIZE, info.size); - TEST_ASSERT_EQUAL(PSA_STORAGE_FLAG_WRITE_ONCE, info.flags); - - status = get_func(stype, 5, 0, TEST_BUFF_SIZE, read_buff, &actual_size); - TEST_ASSERT_EQUAL(PSA_SUCCESS, status); - TEST_ASSERT_EQUAL(TEST_BUFF_SIZE, actual_size); - TEST_ASSERT_EQUAL_MEMORY(write_buff, read_buff, TEST_BUFF_SIZE); - - status = set_func(stype, 5, TEST_BUFF_SIZE, write_buff, PSA_STORAGE_FLAG_WRITE_ONCE); - TEST_ASSERT_EQUAL(PSA_ERROR_NOT_PERMITTED, status); - - status = set_func(stype, 5, TEST_BUFF_SIZE, write_buff, 0); - TEST_ASSERT_EQUAL(PSA_ERROR_NOT_PERMITTED, status); - - status = remove_func(stype, 5); - TEST_ASSERT_EQUAL(PSA_ERROR_NOT_PERMITTED, status); - - info.size = 0; - info.flags = PSA_STORAGE_FLAG_WRITE_ONCE; - status = get_info_func(stype, 5, &info); - TEST_ASSERT_EQUAL(PSA_SUCCESS, status); - TEST_ASSERT_EQUAL(TEST_BUFF_SIZE, info.size); - TEST_ASSERT_EQUAL(PSA_STORAGE_FLAG_WRITE_ONCE, info.flags); -} - -utest::v1::status_t case_its_teardown_handler(const Case *const source, const size_t passed, const size_t failed, const failure_t reason) -{ - psa_status_t status; - status = mbed_psa_reboot_and_request_new_security_state(PSA_LIFECYCLE_ASSEMBLY_AND_TEST); - TEST_ASSERT_EQUAL(PSA_SUCCESS, status); - return greentea_case_teardown_handler(source, passed, failed, reason); -} - -template -utest::v1::status_t case_its_setup_handler(const Case *const source, const size_t index_of_case) -{ - psa_status_t status; - if (stype == its) { - status = mbed_psa_reboot_and_request_new_security_state(PSA_LIFECYCLE_ASSEMBLY_AND_TEST); - TEST_ASSERT_EQUAL(PSA_SUCCESS, status); - } else { - status = psa_ps_reset(); - TEST_ASSERT_EQUAL(PSA_SUCCESS, status); - } -#if DEVICEKEY_ENABLED - DeviceKey::get_instance().generate_root_of_trust(); -#endif - return greentea_case_setup_handler(source, index_of_case); -} - -Case cases[] = { - Case("PSA prot internal storage - Basic", case_its_setup_handler, pits_ps_test, case_its_teardown_handler), - Case("PSA prot internal storage - Write-once", case_its_setup_handler, pits_ps_write_once_test, case_its_teardown_handler), -#if COMPONENT_FLASHIAP - Case("PSA protected storage - Basic", case_its_setup_handler, pits_ps_test), - Case("PSA protected storage - Write-once", case_its_setup_handler, pits_ps_write_once_test) -#endif -}; - -utest::v1::status_t greentea_test_setup(const size_t number_of_cases) -{ - GREENTEA_SETUP(60, "default_auto"); - return greentea_test_setup_handler(number_of_cases); -} - -Specification specification(greentea_test_setup, cases, greentea_test_teardown_handler); - -int main() -{ - return !Harness::run(specification); -} - -#endif // TARGET_PSA -#endif // !defined(MBED_CONF_RTOS_PRESENT) diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TARGET_TFM/COMPONENT_NSPE/interface/src/tfm_ns_lock_rtx.c b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TARGET_TFM/COMPONENT_NSPE/interface/src/tfm_ns_lock_rtx.c new file mode 100644 index 0000000..d12d348 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TARGET_TFM/COMPONENT_NSPE/interface/src/tfm_ns_lock_rtx.c @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2017-2019, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ +#include +#include +#include "cmsis.h" +#include "rtx_os.h" +#include "cmsis_os2.h" +#include "tfm_api.h" +#include "tfm_ns_lock.h" + +/** + * \brief struct ns_lock_state type + */ +struct ns_lock_state +{ + bool init; + osMutexId_t id; +}; + +/** + * \brief ns_lock status + */ +static struct ns_lock_state ns_lock = {.init=false, .id=NULL}; + +/** + * \brief Mutex properties, NS lock + */ + +static osRtxMutex_t ns_lock_cb = { 0 }; + +static const osMutexAttr_t ns_lock_attrib = { + .name = "ns_lock", + .attr_bits = osMutexPrioInherit, + .cb_mem = &ns_lock_cb, + .cb_size = sizeof(ns_lock_cb) +}; + +/** + * \brief NS world, NS lock based dispatcher + */ +__attribute__((weak)) +uint32_t tfm_ns_lock_dispatch(veneer_fn fn, + uint32_t arg0, uint32_t arg1, + uint32_t arg2, uint32_t arg3) +{ + uint32_t result; + + /* Check the NS lock has been initialized */ + if (ns_lock.init == false) { + return TFM_ERROR_GENERIC; + } + + /* TFM request protected by NS lock */ + if (osMutexAcquire(ns_lock.id,osWaitForever) != osOK) { + return TFM_ERROR_GENERIC; + } + + result = fn(arg0, arg1, arg2, arg3); + + if (osMutexRelease(ns_lock.id) != osOK) { + return TFM_ERROR_GENERIC; + } + + return result; +} + +/** + * \brief NS world, Init NS lock + */ +__attribute__((weak)) +enum tfm_status_e tfm_ns_lock_init() +{ + if (ns_lock.init == false) { + ns_lock.id = osMutexNew(&ns_lock_attrib); + ns_lock.init = true; + return TFM_SUCCESS; + } + else { + return TFM_ERROR_GENERIC; + } +} + +bool tfm_ns_lock_get_init_state() +{ + return ns_lock.init; +} + diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TARGET_TFM/COMPONENT_NSPE/interface/src/tfm_psa_ns_api.c b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TARGET_TFM/COMPONENT_NSPE/interface/src/tfm_psa_ns_api.c new file mode 100644 index 0000000..159eef9 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TARGET_TFM/COMPONENT_NSPE/interface/src/tfm_psa_ns_api.c @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2018, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#include "interface/include/psa_client.h" +#include "tfm_ns_lock.h" +#include "tfm_api.h" + +/**** API functions ****/ + +uint32_t psa_framework_version(void) +{ + return tfm_ns_lock_dispatch((veneer_fn)tfm_psa_framework_version_veneer, + 0, + 0, + 0, + 0); +} + +uint32_t psa_version(uint32_t sid) +{ + return tfm_ns_lock_dispatch((veneer_fn)tfm_psa_version_veneer, + sid, + 0, + 0, + 0); +} + +psa_handle_t psa_connect(uint32_t sid, uint32_t minor_version) +{ + return tfm_ns_lock_dispatch((veneer_fn)tfm_psa_connect_veneer, + sid, + minor_version, + 0, + 0); +} + +psa_status_t psa_call(psa_handle_t handle, + const psa_invec *in_vec, + size_t in_len, + psa_outvec *out_vec, + size_t out_len) +{ + /* FixMe: sanity check can be added to offload some NS thread checks from + * TFM secure API + */ + + /* Due to v8M restrictions, TF-M NS API needs to add another layer of + * serialization in order for NS to pass arguments to S + */ + psa_invec in_vecs, out_vecs; + + in_vecs.base = in_vec; + in_vecs.len = in_len; + out_vecs.base = out_vec; + out_vecs.len = out_len; + return tfm_ns_lock_dispatch((veneer_fn)tfm_psa_call_veneer, + (uint32_t)handle, + (uint32_t)&in_vecs, + (uint32_t)&out_vecs, + 0); +} + +void psa_close(psa_handle_t handle) +{ + tfm_ns_lock_dispatch((veneer_fn)tfm_psa_close_veneer, + (uint32_t)handle, + 0, + 0, + 0); +} + diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TARGET_TFM/LICENSE b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TARGET_TFM/LICENSE new file mode 100644 index 0000000..96810fd --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TARGET_TFM/LICENSE @@ -0,0 +1,2 @@ +Unless specifically indicated otherwise in a file, TF-M files in this directory are licensed under the BSD-3-Clause license, +as can be found in: LICENSE-bsd-3-clause.txt diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TARGET_TFM/LICENSE-BSD-3-Clause b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TARGET_TFM/LICENSE-BSD-3-Clause new file mode 100644 index 0000000..476769c --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TARGET_TFM/LICENSE-BSD-3-Clause @@ -0,0 +1,26 @@ +Copyright 2019 Arm Limited and affiliates. +SPDX-License-Identifier: BSD-3-Clause + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. Neither the name of the copyright holder nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TARGET_TFM/interface/include/psa_client.h b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TARGET_TFM/interface/include/psa_client.h new file mode 100644 index 0000000..71adb80 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TARGET_TFM/interface/include/psa_client.h @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2018-2019, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#ifndef __PSA_CLIENT_H__ +#define __PSA_CLIENT_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +/*********************** PSA Client Macros and Types *************************/ + +#define PSA_FRAMEWORK_VERSION (0x0100) + +#define PSA_VERSION_NONE (0) + +/* PSA response types */ +#define PSA_SUCCESS (0) +#define PSA_CONNECTION_REFUSED (INT32_MIN + 1) +#define PSA_CONNECTION_BUSY (INT32_MIN + 2) +#define PSA_DROP_CONNECTION (INT32_MIN) + +/* PSA message handles */ +#define PSA_NULL_HANDLE ((psa_handle_t)0) + +typedef int32_t psa_status_t; +typedef int32_t psa_handle_t; + +/** + * A read-only input memory region provided to an RoT Service. + */ +typedef struct psa_invec { + const void *base; /*!< the start address of the memory buffer */ + size_t len; /*!< the size in bytes */ +} psa_invec; + +/** + * A writable output memory region provided to an RoT Service. + */ +typedef struct psa_outvec { + void *base; /*!< the start address of the memory buffer */ + size_t len; /*!< the size in bytes */ +} psa_outvec; + +/*************************** PSA Client API **********************************/ + +/** + * \brief Retrieve the version of the PSA Framework API that is implemented. + * + * \return version The version of the PSA Framework implementation + * that is providing the runtime services to the + * caller. The major and minor version are encoded + * as follows: + * \arg version[15:8] -- major version number. + * \arg version[7:0] -- minor version number. + */ +uint32_t psa_framework_version(void); + +/** + * \brief Retrieve the minor version of an RoT Service or indicate that it is + * not present on this system. + * + * \param[in] sid ID of the RoT Service to query. + * + * \retval PSA_VERSION_NONE The RoT Service is not implemented, or the + * caller is not permitted to access the service. + * \retval > 0 The minor version of the implemented RoT + * Service. + */ +uint32_t psa_version(uint32_t sid); + +/** + * \brief Connect to an RoT Service by its SID. + * + * \param[in] sid ID of the RoT Service to connect to. + * \param[in] minor_version Requested version of the RoT Service. + * + * \retval > 0 A handle for the connection. + * \retval PSA_CONNECTION_REFUSED The SPM or RoT Service has refused the + * connection. + * \retval PSA_CONNECTION_BUSY The SPM or RoT Service cannot make the + * connection at the moment. + * \retval "Does not return" The RoT Service ID and version are not + * supported, or the caller is not permitted to + * access the service. + */ +psa_handle_t psa_connect(uint32_t sid, uint32_t minor_version); + +/** + * \brief Call an RoT Service on an established connection. + * + * \param[in] handle A handle to an established connection. + * \param[in] in_vec Array of input \ref psa_invec structures. + * \param[in] in_len Number of input \ref psa_invec structures. + * \param[in/out] out_vec Array of output \ref psa_outvec structures. + * \param[in] out_len Number of output \ref psa_outvec structures. + * + * \retval >=0 RoT Service-specific status value. + * \retval <0 RoT Service-specific error code. + * \retval PSA_DROP_CONNECTION The connection has been dropped by the RoT + * Service. This indicates that either this or + * a previous message was invalid. + * \retval "Does not return" The call is invalid, one or more of the + * following are true: + * \arg An invalid handle was passed. + * \arg The connection is already handling a request. + * \arg An invalid memory reference was provided. + * \arg in_len + out_len > PSA_MAX_IOVEC. + * \arg The message is unrecognized by the RoT + * Service or incorrectly formatted. + */ +psa_status_t psa_call(psa_handle_t handle, + const psa_invec *in_vec, + size_t in_len, + psa_outvec *out_vec, + size_t out_len); + +/** + * \brief Close a connection to an RoT Service. + * + * \param[in] handle A handle to an established connection, or the + * null handle. + * + * \retval void Success. + * \retval "Does not return" The call is invalid, one or more of the + * following are true: + * \arg An invalid handle was provided that is not + * the null handle. + * \arg The connection is handling a request. + */ +void psa_close(psa_handle_t handle); + +#ifdef __cplusplus +} +#endif + +#endif /* __PSA_CLIENT_H__ */ diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TARGET_TFM/interface/include/psa_service.h b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TARGET_TFM/interface/include/psa_service.h new file mode 100644 index 0000000..6453aed --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TARGET_TFM/interface/include/psa_service.h @@ -0,0 +1,250 @@ +/* + * Copyright (c) 2018-2019, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#ifndef __PSA_SERVICE_H__ +#define __PSA_SERVICE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/********************** PSA Secure Partition Macros and Types ****************/ + +/* PSA wait timeouts */ +#define PSA_POLL (0x00000000u) +#define PSA_BLOCK (0x80000000u) + +/* A mask value that includes all Secure Partition signals */ +#define PSA_WAIT_ANY (~0u) + +/* Doorbell signal */ +#define PSA_DOORBELL (0x00000008u) + +/* PSA message types */ +#define PSA_IPC_CONNECT (1) +#define PSA_IPC_CALL (2) +#define PSA_IPC_DISCONNECT (3) + +/* Maximum number of input and output vectors */ +#define PSA_MAX_IOVEC (4) + +/* Return code from psa_get() */ +#define PSA_ERR_NOMSG (INT32_MIN + 3) + +/* Store a set of one or more Secure Partition signals */ +typedef uint32_t psa_signal_t; + +/** + * Describe a message received by an RoT Service after calling \ref psa_get(). + */ +typedef struct psa_msg_t { + uint32_t type; /* One of the following values: + * \ref PSA_IPC_CONNECT + * \ref PSA_IPC_CALL + * \ref PSA_IPC_DISCONNECT + */ + psa_handle_t handle; /* A reference generated by the SPM to the + * message returned by psa_get(). + */ + int32_t client_id; /* Partition ID of the sender of the message */ + void *rhandle; /* Be useful for binding a connection to some + * application-specific data or function + * pointer within the RoT Service + * implementation. + */ + size_t in_size[PSA_MAX_IOVEC]; /* Provide the size of each client input + * vector in bytes. + */ + size_t out_size[PSA_MAX_IOVEC];/* Provide the size of each client output + * vector in bytes. + */ +} psa_msg_t; + +/************************* PSA Secure Partition API **************************/ + +/** + * \brief Return the Secure Partition interrupt signals that have been asserted + * from a subset of signals provided by the caller. + * + * \param[in] signal_mask A set of signals to query. Signals that are not + * in this set will be ignored. + * \param[in] timeout Specify either blocking \ref PSA_BLOCK or + * polling \ref PSA_POLL operation. + * + * \retval >0 At least one signal is asserted. + * \retval 0 No signals are asserted. This is only seen when + * a polling timeout is used. + */ +psa_signal_t psa_wait(psa_signal_t signal_mask, uint32_t timeout); + +/** + * \brief Retrieve the message which corresponds to a given RoT Service signal + * and remove the message from the RoT Service queue. + * + * \param[in] signal The signal value for an asserted RoT Service. + * \param[out] msg Pointer to \ref psa_msg_t object for receiving + * the message. + * + * \retval PSA_SUCCESS Success, *msg will contain the delivered + * message. + * \retval PSA_ERR_NOMSG Message could not be delivered. + * \retval "Does not return" The call is invalid because one or more of the + * following are true: + * \arg signal has more than a single bit set. + * \arg signal does not correspond to an RoT Service. + * \arg The RoT Service signal is not currently + * asserted. + * \arg The msg pointer provided is not a valid memory + * reference. + */ +psa_status_t psa_get(psa_signal_t signal, psa_msg_t *msg); + +/** + * \brief Associate some RoT Service private data with a client connection. + * + * \param[in] msg_handle Handle for the client's message. + * \param[in] rhandle Reverse handle allocated by the RoT Service. + * + * \retval void Success, rhandle will be provided with all + * subsequent messages delivered on this + * connection. + * \retval "Does not return" msg_handle is invalid. + */ +void psa_set_rhandle(psa_handle_t msg_handle, void *rhandle); + +/** + * \brief Read a message parameter or part of a message parameter from a client + * input vector. + * + * \param[in] msg_handle Handle for the client's message. + * \param[in] invec_idx Index of the input vector to read from. Must be + * less than \ref PSA_MAX_IOVEC. + * \param[out] buffer Buffer in the Secure Partition to copy the + * requested data to. + * \param[in] num_bytes Maximum number of bytes to be read from the + * client input vector. + * + * \retval >0 Number of bytes copied. + * \retval 0 There was no remaining data in this input + * vector. + * \retval "Does not return" The call is invalid, one or more of the + * following are true: + * \arg msg_handle is invalid. + * \arg msg_handle does not refer to a + * \ref PSA_IPC_CALL message. + * \arg invec_idx is equal to or greater than + * \ref PSA_MAX_IOVEC. + * \arg the memory reference for buffer is invalid or + * not writable. + */ +size_t psa_read(psa_handle_t msg_handle, uint32_t invec_idx, + void *buffer, size_t num_bytes); + +/** + * \brief Skip over part of a client input vector. + * + * \param[in] msg_handle Handle for the client's message. + * \param[in] invec_idx Index of input vector to skip from. Must be + * less than \ref PSA_MAX_IOVEC. + * \param[in] num_bytes Maximum number of bytes to skip in the client + * input vector. + * + * \retval >0 Number of bytes skipped. + * \retval 0 There was no remaining data in this input + * vector. + * \retval "Does not return" The call is invalid, one or more of the + * following are true: + * \arg msg_handle is invalid. + * \arg msg_handle does not refer to a + * \ref PSA_IPC_CALL message. + * \arg invec_idx is equal to or greater than + * \ref PSA_MAX_IOVEC. + */ +size_t psa_skip(psa_handle_t msg_handle, uint32_t invec_idx, size_t num_bytes); + +/** + * \brief Write a message response to a client output vector. + * + * \param[in] msg_handle Handle for the client's message. + * \param[out] outvec_idx Index of output vector in message to write to. + * Must be less than \ref PSA_MAX_IOVEC. + * \param[in] buffer Buffer with the data to write. + * \param[in] num_bytes Number of bytes to write to the client output + * vector. + * + * \retval void Success + * \retval "Does not return" The call is invalid, one or more of the + * following are true: + * \arg msg_handle is invalid. + * \arg msg_handle does not refer to a + * \ref PSA_IPC_CALL message. + * \arg outvec_idx is equal to or greater than + * \ref PSA_MAX_IOVEC. + * \arg The memory reference for buffer is invalid. + * \arg The call attempts to write data past the end + * of the client output vector. + */ +void psa_write(psa_handle_t msg_handle, uint32_t outvec_idx, + const void *buffer, size_t num_bytes); + +/** + * \brief Complete handling of a specific message and unblock the client. + * + * \param[in] msg_handle Handle for the client's message. + * \param[in] status Message result value to be reported to the + * client. + * + * \retval void Success. + * \retval "Does not return" The call is invalid, one or more of the + * following are true: + * \arg msg_handle is invalid. + * \arg An invalid status code is specified for the + * type of message. + */ +void psa_reply(psa_handle_t msg_handle, psa_status_t status); + +/** + * \brief Send a PSA_DOORBELL signal to a specific Secure Partition. + * + * \param[in] partition_id Secure Partition ID of the target partition. + * + * \retval void Success. + * \retval "Does not return" partition_id does not correspond to a Secure + * Partition. + */ +void psa_notify(int32_t partition_id); + +/** + * \brief Clear the PSA_DOORBELL signal. + * + * \retval void Success. + * \retval "Does not return" The Secure Partition's doorbell signal is not + * currently asserted. + */ +void psa_clear(void); + +/** + * \brief Inform the SPM that an interrupt has been handled (end of interrupt). + * + * \param[in] irq_signal The interrupt signal that has been processed. + * + * \retval void Success. + * \retval "Does not return" The call is invalid, one or more of the + * following are true: + * \arg irq_signal is not an interrupt signal. + * \arg irq_signal indicates more than one signal. + * \arg irq_signal is not currently asserted. + */ +void psa_eoi(psa_signal_t irq_signal); + +#ifdef __cplusplus +} +#endif + +#endif /* __PSA_SERVICE_H__ */ diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TARGET_TFM/interface/include/tfm_api.h b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TARGET_TFM/interface/include/tfm_api.h new file mode 100644 index 0000000..d6ce689 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TARGET_TFM/interface/include/tfm_api.h @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2017-2019, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#ifndef __TFM_API_H__ +#define __TFM_API_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "psa_client.h" + +#define TFM_INVALID_CLIENT_ID 0 + +/** + * \brief Checks if the provided client ID is a secure client ID. + * + * \param[in] client_id Client ID to check + * + * \return Returns 1 if the client Id is secure. Otherwise, returns 0. + */ +#define TFM_CLIENT_ID_IS_S(client_id) ((client_id)>0) + +/** + * \brief Checks if the provided client ID is a non-secure client ID. + * + * \param[in] client_id Client ID to check + * + * \return Returns 1 if the client Id is non-secure. Otherwise, returns 0. + */ +#define TFM_CLIENT_ID_IS_NS(client_id) ((client_id)<0) + +/* Maximum number of input and output vectors */ +#define PSA_MAX_IOVEC (4) + +/* FixMe: sort out DEBUG compile option and limit return value options + * on external interfaces */ +/* For secure functions using prorietary signatures + * TFM will only return values recognized and parsed by TFM core. + * Service return codes are not automatically passed on to REE. + * Any non-zero return value is interpreted as an error that may trigger + * TEE error handling flow. + * For secure functions using the veneers in secure_fw/ns_callable/tfm_veneers.c + * (iovec API) this limitation does not apply. + */ +enum tfm_status_e +{ + TFM_SUCCESS = 0, + TFM_PARTITION_BUSY, + TFM_ERROR_SECURE_DOMAIN_LOCKED, + TFM_ERROR_INVALID_PARAMETER, + TFM_ERROR_PARTITION_NON_REENTRANT, + TFM_ERROR_NS_THREAD_MODE_CALL, + TFM_ERROR_NOT_INITIALIZED, + TFM_ERROR_NO_ACTIVE_PARTITION, + TFM_ERROR_INVALID_EXC_MODE, + TFM_SECURE_LOCK_FAILED, + TFM_SECURE_UNLOCK_FAILED, + TFM_ERROR_GENERIC = 0x1F, + TFM_PARTITION_SPECIFIC_ERROR_MIN, +}; + +//==================== Secure function declarations ==========================// + +/** + * \brief Assign client ID to the current TZ context + * + * \param[in] ns_client_id The client ID to be assigned to the current + * context + * \return TFM_SUCCESS if the client ID assigned successfully, an error code + * according to \ref tfm_status_e in case of error. + * + * \note This function have to be called from handler mode. + */ +enum tfm_status_e tfm_register_client_id (int32_t ns_client_id); + +/** + * \brief Retrieve the version of the PSA Framework API that is implemented + * + * \return The version of the PSA Framework + */ +uint32_t tfm_psa_framework_version_veneer(void); + +/** + * \brief Return version of secure function provided by secure binary + * + * \param[in] sid ID of secure service + * + * \return Version number of secure function + */ +uint32_t tfm_psa_version_veneer(uint32_t sid); + +/** + * \brief Connect to secure function + * + * \param[in] sid ID of secure service + * \param[in] minor_version Minor version of SF requested by client + * + * \return Returns handle to connection + */ +psa_handle_t tfm_psa_connect_veneer(uint32_t sid, uint32_t minor_version); + +/** + * \brief Call a secure function referenced by a connection handle + * + * \param[in] handle Handle to connection + * \param[in] in_vecs invec containing pointer/count of input vectors + * \param[in] out_vecs outvec containing pointer/count of output vectors + * + * \return Returns \ref psa_status_t status code + */ +psa_status_t tfm_psa_call_veneer(psa_handle_t handle, + const psa_invec *in_vecs, + psa_outvec *out_vecs); + +/** + * \brief Close connection to secure function referenced by a connection handle + * + * \param[in] handle Handle to connection + * + * \return Returns \ref psa_status_t status code + */ +psa_status_t tfm_psa_close_veneer(psa_handle_t handle); + +//================ End Secure function declarations ==========================// + +#ifdef __cplusplus +} +#endif + +#endif /* __TFM_API_H__ */ diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TARGET_TFM/interface/include/tfm_ns_lock.h b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TARGET_TFM/interface/include/tfm_ns_lock.h new file mode 100644 index 0000000..d9acd00 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TARGET_TFM/interface/include/tfm_ns_lock.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2017-2019, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ +#ifndef __TFM_NS_LOCK_H__ +#define __TFM_NS_LOCK_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "tfm_api.h" + +typedef int32_t (*veneer_fn) (uint32_t arg0, uint32_t arg1, + uint32_t arg2, uint32_t arg3); + +/** + * \brief NS world, NS lock based dispatcher + * + * \details To be called from the wrapper API interface + */ + +uint32_t tfm_ns_lock_dispatch(veneer_fn fn, + uint32_t arg0, uint32_t arg1, + uint32_t arg2, uint32_t arg3); + +/** + * \brief NS world, Init NS lock + * + * \details Needs to be called during non-secure app init + * to initialize the TFM NS lock object + */ +enum tfm_status_e tfm_ns_lock_init(); + +#ifdef __cplusplus +} +#endif + +#endif /* __TFM_NS_LOCK_H__ */ diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TARGET_TFM/interface/include/tfm_ns_svc.h b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TARGET_TFM/interface/include/tfm_ns_svc.h new file mode 100644 index 0000000..366a70a --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TARGET_TFM/interface/include/tfm_ns_svc.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2017-2019, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#include +#include + +#ifndef __TFM_NS_SVC_H__ +#define __TFM_NS_SVC_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Include all the SVC handler headers + */ +#include "tfm_nspm_svc_handler.h" + +/** + * \brief Macro to encode an svc instruction + * + */ +#define SVC(code) __ASM volatile("svc %0" : : "I" (code)) + +/** + * \def LIST_SVC_NSPM + * + * \brief This is an X macro which lists + * the SVC interface exposed by TF-M + * for the NS OS. + * + */ +#define LIST_SVC_NSPM \ + X(SVC_TFM_NSPM_REGISTER_CLIENT_ID, tfm_nspm_svc_register_client_id) \ + +/** + * \brief Numbers associated to each SVC available + * + * \details Start from 1 as 0 is reserved by RTX + */ +enum tfm_svc_num { + SVC_INVALID = 0, + +#define X(SVC_ENUM, SVC_HANDLER) SVC_ENUM, + + /* SVC API for Services */ +#ifdef TFM_NS_CLIENT_IDENTIFICATION + LIST_SVC_NSPM +#endif + +#undef X + + /* add all the new entries above this line */ + SVC_TFM_MAX, +}; + +/* number of user SVC functions */ +#define USER_SVC_COUNT ((uint32_t)SVC_TFM_MAX - 1) + +#ifdef __cplusplus +} +#endif + +#endif /* __TFM_NS_SVC_H__ */ diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TARGET_TFM/interface/include/tfm_nspm_svc_handler.h b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TARGET_TFM/interface/include/tfm_nspm_svc_handler.h new file mode 100644 index 0000000..73f75a9 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TARGET_TFM/interface/include/tfm_nspm_svc_handler.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2018, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#ifndef __TFM_NSPM_SVC_HANDLER_H__ +#define __TFM_NSPM_SVC_HANDLER_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Reports the client ID of this task to TF-M (SVC function) + * + * \param [in] client_id Client ID to register. + * + * \return Returns 1 if the client ID was successfully reported 0 otherwise + */ +uint32_t tfm_nspm_svc_register_client_id(uint32_t client_id); + +#ifdef __cplusplus +} +#endif + +#endif /* __TFM_NSPM_SVC_HANDLER_H__ */ diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TARGET_TFM/mbed_lib.json b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TARGET_TFM/mbed_lib.json new file mode 100644 index 0000000..0cf8e65 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TARGET_TFM/mbed_lib.json @@ -0,0 +1,29 @@ +{ + "name": "tfm", + "macros": [ + "TFM_PSA_API", "MBED_TZ_DEFAULT_ACCESS=1" + ], + "config": { + "level": { + "help": "TFM security level", + "macro_name": "TFM_LVL", + "value": 1 + }, + "handle_pool_size": { + "help": "maximum number of handles that can be opened at the same time", + "macro_name": "TFM_CONN_HANDLE_MAX_NUM", + "value": 10 + }, + "rot_pool_size": { + "help": "maximum number of RoT services allowed", + "macro_name": "TFM_SPM_MAX_ROT_SERV_NUM", + "value": 32 + }, + "message_pool_size": { + "help": "maximum number of active messages allowed", + "macro_name": "TFM_MSG_QUEUE_MAX_MSG_NUM", + "value": 10 + } + } +} + diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/attestation/main.cpp b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/attestation/main.cpp new file mode 100755 index 0000000..c7305ca --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/attestation/main.cpp @@ -0,0 +1,164 @@ +/* +* Copyright (c) 2019 ARM Limited. All rights reserved. +* +* SPDX-License-Identifier: Apache-2.0 +* +* Licensed under the Apache License, Version 2.0 (the License); you may +* not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an AS IS BASIS, WITHOUT +* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#if !defined(MBED_CONF_RTOS_PRESENT) +#error [NOT_SUPPORTED] PSA attestation test cases require RTOS to run. +#else + +#include "psa/crypto.h" + +#if ((!defined(TARGET_PSA)) || (!defined(MBEDTLS_PSA_CRYPTO_C))) +#error [NOT_SUPPORTED] Mbed Crypto is OFF - skipping. +#else + +#include "greentea-client/test_env.h" +#include "unity/unity.h" +#include "utest/utest.h" +#include "psa/lifecycle.h" +#include "psa_initial_attestation_api.h" +#include "psa_attest_inject_key.h" +#include +#include + +#include "entropy.h" +#include "entropy_poll.h" + +/* MAX value support macro */ +#if !defined(MAX) +#define MAX(a,b) (((a)>(b))?(a):(b)) +#endif + +#define MBEDTLS_PSA_INJECT_ENTROPY_MIN_SIZE \ +MAX(MBEDTLS_ENTROPY_MIN_PLATFORM, MBEDTLS_ENTROPY_BLOCK_SIZE) + +using namespace utest::v1; + +utest::v1::status_t greentea_test_setup(const size_t number_of_cases) +{ + GREENTEA_SETUP(60, "default_auto"); + return greentea_test_setup_handler(number_of_cases); +} + +#define PSA_ATTESTATION_PRIVATE_KEY_ID 17 + +static const uint8_t private_key_data[] = { + 0x49, 0xc9, 0xa8, 0xc1, 0x8c, 0x4b, 0x88, 0x56, + 0x38, 0xc4, 0x31, 0xcf, 0x1d, 0xf1, 0xc9, 0x94, + 0x13, 0x16, 0x09, 0xb5, 0x80, 0xd4, 0xfd, 0x43, + 0xa0, 0xca, 0xb1, 0x7d, 0xb2, 0xf1, 0x3e, 0xee +}; + +static const uint8_t public_key_data[] = { + 0x04, 0x77, 0x72, 0x65, 0x6f, 0x81, 0x4b, 0x39, + 0x92, 0x79, 0xd5, 0xe1, 0xf1, 0x78, 0x1f, 0xac, + 0x6f, 0x09, 0x9a, 0x3c, 0x5c, 0xa1, 0xb0, 0xe3, + 0x53, 0x51, 0x83, 0x4b, 0x08, 0xb6, 0x5e, 0x0b, + 0x57, 0x25, 0x90, 0xcd, 0xaf, 0x8f, 0x76, 0x93, + 0x61, 0xbc, 0xf3, 0x4a, 0xcf, 0xc1, 0x1e, 0x5e, + 0x07, 0x4e, 0x84, 0x26, 0xbd, 0xde, 0x04, 0xbe, + 0x6e, 0x65, 0x39, 0x45, 0x44, 0x96, 0x17, 0xde, + 0x45 +}; + +#define TEST_TOKEN_SIZE (0x200) +#define TEST_CHALLENGE_OBJ_SIZE (32u) + +#define CHALLENGE_FOR_TEST 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, \ + 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, \ + 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, \ + 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF + +static uint8_t token_buffer[TEST_TOKEN_SIZE]; +static uint8_t challenge_buffer[TEST_CHALLENGE_OBJ_SIZE] = {CHALLENGE_FOR_TEST}; + +static void check_initial_attestation_get_token() +{ + psa_status_t status = PSA_SUCCESS; + size_t exported_length; + uint8_t exported[sizeof(public_key_data)]; + enum psa_attest_err_t attest_err = PSA_ATTEST_ERR_SUCCESS; + uint32_t token_size; + + status = psa_crypto_init(); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + status = psa_attestation_inject_key(private_key_data, + sizeof(private_key_data), + PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_CURVE_SECP_R1), + exported, + sizeof(exported), + &exported_length); + + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + TEST_ASSERT_EQUAL(sizeof(public_key_data), exported_length); + TEST_ASSERT_EQUAL(0, memcmp(public_key_data, exported, exported_length)); + + attest_err = psa_initial_attest_get_token_size(TEST_CHALLENGE_OBJ_SIZE, + &token_size); + + TEST_ASSERT_EQUAL(PSA_ATTEST_ERR_SUCCESS, attest_err); + + attest_err = psa_initial_attest_get_token(challenge_buffer, + TEST_CHALLENGE_OBJ_SIZE, + token_buffer, + &token_size); + + TEST_ASSERT_EQUAL(PSA_ATTEST_ERR_SUCCESS, attest_err); +} +/***************************************************************************************/ + +utest::v1::status_t case_teardown_handler(const Case *const source, const size_t passed, const size_t failed, const failure_t reason) +{ + psa_key_handle_t handle; + psa_open_key(PSA_ATTESTATION_PRIVATE_KEY_ID, &handle); + psa_destroy_key(handle); + mbedtls_psa_crypto_free(); + return greentea_case_teardown_handler(source, passed, failed, reason); +} + +utest::v1::status_t case_setup_handler(const Case *const source, const size_t index_of_case) +{ + psa_status_t status; + status = mbed_psa_reboot_and_request_new_security_state(PSA_LIFECYCLE_ASSEMBLY_AND_TEST); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); +#if (defined(COMPONENT_PSA_SRV_IPC) || defined(MBEDTLS_ENTROPY_NV_SEED)) + uint8_t seed[MBEDTLS_PSA_INJECT_ENTROPY_MIN_SIZE] = {0}; + /* inject some seed for test*/ + for (int i = 0; i < MBEDTLS_PSA_INJECT_ENTROPY_MIN_SIZE; ++i) { + seed[i] = i; + } + + /* don't really care if this succeeds this is just to make crypto init pass*/ + mbedtls_psa_inject_entropy(seed, MBEDTLS_PSA_INJECT_ENTROPY_MIN_SIZE); +#endif + return greentea_case_setup_handler(source, index_of_case); +} + + +Case cases[] = { + Case("PSA attestation get token", case_setup_handler, check_initial_attestation_get_token, case_teardown_handler), +}; + +Specification specification(greentea_test_setup, cases); + +int main() +{ + return !Harness::run(specification); +} + +#endif // ((!defined(TARGET_PSA)) || (!defined(MBEDTLS_PSA_CRYPTO_C))) +#endif // !defined(MBED_CONF_RTOS_PRESENT) diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_attestation/psa_attestation_testlist.md b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_attestation/psa_attestation_testlist.md new file mode 100644 index 0000000..d8d7f10 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_attestation/psa_attestation_testlist.md @@ -0,0 +1,22 @@ +# PSA Initial Attestation Testcase checklist + +| Test | Return value | API | Test Algorithm | Test Cases | +|-----------|--------------------------------------|-------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| test_a001 | PSA_ATTEST_ERR_SUCCESS | psa_initial_attest_get_token()
psa_initial_attest_get_token_size() | 1. Provide correct inputs to API with described challenge sizes
2. Expect API to return this define as return value each time
3. Verify the token | 1. Challenge_size = 32
2. Challenge_size = 48
3. Challenge_size = 64 | +| | PSA_ATTEST_ERR_INVALID_INPUT | psa_initial_attest_get_token()
psa_initial_attest_get_token_size() | 1. Provide described challenge sizes to the API along with other valid parameters
2. Expect API to return this define as return value each time | 1. Challenge_size is zero
2. Invalid challenge size between 0 and 32
3. Invalid challenge size between 32 and 64
4. Challenge_size is greater than MAX_CHALLENGE_SIZE | +| | PSA_ATTEST_ERR_TOKEN_BUFFER_OVERFLOW | psa_initial_attest_get_token() | 1. Provide described taken size to the API along with other valid parameters
2. Expect API to return this define as return value each time | Pass the token_size which less than actual/required token size | +| | PSA_ATTEST_ERR_INIT_FAILED | psa_initial_attest_get_token()
psa_initial_attest_get_token_size() | Can't simulate. Test can't generate stimulus where attestation initialisation fails | | +| | PSA_ATTEST_ERR_CLAIM_UNAVAILABLE | psa_initial_attest_get_token() | Can't simulate. Test can't generate stimulus where claim can unavailable | | +| | PSA_ATTEST_ERR_GENERAL | psa_initial_attest_get_token()
psa_initial_attest_get_token_size() | Can't simulate. Test can't generate stimulus where unexpected error happened during API operation | | + +## Note + +1. In verifying the token, only the data type of claims and presence of the mandatory claims are checked and the values of the claims are not checked. +2. Checks related to token signature validation will be part of future release + +# License +Arm PSA test suite is distributed under Apache v2.0 License. + +-------------- + +*Copyright (c) 2019, Arm Limited and Contributors. All rights reserved.* diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_attestation/test_a001/main.c b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_attestation/test_a001/main.c new file mode 100644 index 0000000..2bdbffd --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_attestation/test_a001/main.c @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2020, Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "val_interfaces.h" +#include "pal_mbed_os_intf.h" + +#if !defined(MBED_CONF_RTOS_PRESENT) +#error [NOT_SUPPORTED] PSA compliance attestation test cases require RTOS to run. +#else +void test_entry_a001(val_api_t *val_api, psa_api_t *psa_api); + +int main(void) +{ + test_start(test_entry_a001, COMPLIANCE_TEST_ATTESTATION); +} +#endif diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_attestation/test_a001/test_a001.c b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_attestation/test_a001/test_a001.c new file mode 100644 index 0000000..edb8e59 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_attestation/test_a001/test_a001.c @@ -0,0 +1,105 @@ +/** @file + * Copyright (c) 2019, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ + +#include "val_interfaces.h" +#include "val_target.h" +#include "test_a001.h" +#include "test_data.h" + +client_test_t test_a001_attestation_list[] = { + NULL, + psa_initial_attestation_get_token_test, + psa_initial_attestation_get_token_size_test, + NULL, +}; + +static int g_test_count = 1; + +int32_t psa_initial_attestation_get_token_test(caller_security_t caller) +{ + int num_checks = sizeof(check1)/sizeof(check1[0]); + uint32_t i, status, token_size; + uint8_t challenge[PSA_INITIAL_ATTEST_CHALLENGE_SIZE_64+1]; + uint8_t token_buffer[TOKEN_SIZE]; + + for (i = 0; i < num_checks; i++) + { + val->print(PRINT_TEST, "[Check %d] ", g_test_count++); + val->print(PRINT_TEST, check1[i].test_desc, 0); + + memset(challenge, 0x2a, sizeof(challenge)); + memset(token_buffer, 0, sizeof(token_buffer)); + + status = val->attestation_function(VAL_INITIAL_ATTEST_GET_TOKEN_SIZE, + check1[i].challenge_size, &token_size); + if (status != PSA_SUCCESS) + { + if (check1[i].challenge_size != PSA_INITIAL_ATTEST_CHALLENGE_SIZE_32 || + check1[i].challenge_size != PSA_INITIAL_ATTEST_CHALLENGE_SIZE_48 || + check1[i].challenge_size != PSA_INITIAL_ATTEST_CHALLENGE_SIZE_64) + { + token_size = check1[i].token_size; + check1[i].challenge_size = check1[i].actual_challenge_size; + } + else + return status; + } + + status = val->attestation_function(VAL_INITIAL_ATTEST_GET_TOKEN, challenge, + check1[i].challenge_size, token_buffer, &token_size); + TEST_ASSERT_EQUAL(status, check1[i].expected_status, TEST_CHECKPOINT_NUM(1)); + + if (check1[i].expected_status != PSA_SUCCESS) + continue; + + /* Validate the token */ + status = val->attestation_function(VAL_INITIAL_ATTEST_VERIFY_TOKEN, challenge, + check1[i].challenge_size, token_buffer, token_size); + TEST_ASSERT_EQUAL(status, PSA_SUCCESS, TEST_CHECKPOINT_NUM(2)); + } + + return VAL_STATUS_SUCCESS; +} + +int32_t psa_initial_attestation_get_token_size_test(caller_security_t caller) +{ + int num_checks = sizeof(check2)/sizeof(check2[0]); + uint32_t i, status, token_size; + + for (i = 0; i < num_checks; i++) + { + val->print(PRINT_TEST, "[Check %d] ", g_test_count++); + val->print(PRINT_TEST, check2[i].test_desc, 0); + + status = val->attestation_function(VAL_INITIAL_ATTEST_GET_TOKEN_SIZE, + check2[i].challenge_size, &token_size); + + TEST_ASSERT_EQUAL(status, check2[i].expected_status, TEST_CHECKPOINT_NUM(1)); + + if (check2[i].expected_status != PSA_SUCCESS) + continue; + + if (token_size < check2[i].challenge_size) + { + val->print(PRINT_ERROR, "Token size less than challenge size\n", 0); + return VAL_STATUS_INSUFFICIENT_SIZE; + } + } + + return VAL_STATUS_SUCCESS; +} + diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_attestation/test_a001/test_a001.h b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_attestation/test_a001/test_a001.h new file mode 100644 index 0000000..e066ee8 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_attestation/test_a001/test_a001.h @@ -0,0 +1,33 @@ +/** @file + * Copyright (c) 2019, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ +#ifndef _TEST_A001_CLIENT_TESTS_H_ +#define _TEST_A001_CLIENT_TESTS_H_ + +#include "val_attestation.h" +#define test_entry CONCAT(test_entry_, a001) +#define val CONCAT(val,test_entry) +#define psa CONCAT(psa,test_entry) + +#define TOKEN_SIZE 512 + +extern val_api_t *val; +extern psa_api_t *psa; +extern client_test_t test_a001_attestation_list[]; + +int32_t psa_initial_attestation_get_token_test(caller_security_t caller); +int32_t psa_initial_attestation_get_token_size_test(caller_security_t caller); +#endif /* _TEST_A001_CLIENT_TESTS_H_ */ diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_attestation/test_a001/test_data.h b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_attestation/test_a001/test_data.h new file mode 100644 index 0000000..bfeba55 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_attestation/test_a001/test_data.h @@ -0,0 +1,103 @@ +/** @file + * Copyright (c) 2019, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ + +#include "val_attestation.h" + +typedef struct { + char test_desc[100]; + uint32_t challenge_size; + uint32_t actual_challenge_size; + uint32_t token_size; + psa_status_t expected_status; +} test_data; + + +static test_data check1[] = { +{"Test psa_initial_attestation_get_token with Challenge 32\n", + PSA_INITIAL_ATTEST_CHALLENGE_SIZE_32, PSA_INITIAL_ATTEST_CHALLENGE_SIZE_32, TOKEN_SIZE, PSA_SUCCESS +}, + +{"Test psa_initial_attestation_get_token with Challenge 48\n", + PSA_INITIAL_ATTEST_CHALLENGE_SIZE_48, PSA_INITIAL_ATTEST_CHALLENGE_SIZE_48, TOKEN_SIZE, PSA_SUCCESS +}, + +{"Test psa_initial_attestation_get_token with Challenge 64\n", + PSA_INITIAL_ATTEST_CHALLENGE_SIZE_64, PSA_INITIAL_ATTEST_CHALLENGE_SIZE_64, TOKEN_SIZE, PSA_SUCCESS +}, + +{"Test psa_initial_attestation_get_token with zero challenge size\n", + 0, 0, TOKEN_SIZE, PSA_ATTEST_ERR_INVALID_INPUT +}, + +{"Test psa_initial_attestation_get_token with small challenge size\n", + PSA_INITIAL_ATTEST_CHALLENGE_SIZE_32-1, PSA_INITIAL_ATTEST_CHALLENGE_SIZE_32-1, + TOKEN_SIZE, PSA_ATTEST_ERR_INVALID_INPUT +}, + +{"Test psa_initial_attestation_get_token with invalid challenge size\n", + PSA_INITIAL_ATTEST_CHALLENGE_SIZE_32+1, PSA_INITIAL_ATTEST_CHALLENGE_SIZE_32+1, + TOKEN_SIZE, PSA_ATTEST_ERR_INVALID_INPUT +}, + +{"Test psa_initial_attestation_get_token with large challenge size\n", + MAX_CHALLENGE_SIZE+1, MAX_CHALLENGE_SIZE+1, TOKEN_SIZE, PSA_ATTEST_ERR_INVALID_INPUT +}, + +{"Test psa_initial_attestation_get_token with zero as token size\n", + PSA_INITIAL_ATTEST_CHALLENGE_SIZE_32-1, PSA_INITIAL_ATTEST_CHALLENGE_SIZE_32, + 0, PSA_ATTEST_ERR_INVALID_INPUT +}, + +{"Test psa_initial_attestation_get_token with small token size\n", + PSA_INITIAL_ATTEST_CHALLENGE_SIZE_32-1, PSA_INITIAL_ATTEST_CHALLENGE_SIZE_32, + PSA_INITIAL_ATTEST_CHALLENGE_SIZE_32-1, PSA_ATTEST_ERR_TOKEN_BUFFER_OVERFLOW +}, +}; + +static test_data check2[] = { +{"Test psa_initial_attestation_get_token_size with Challenge 32\n", + PSA_INITIAL_ATTEST_CHALLENGE_SIZE_32, PSA_INITIAL_ATTEST_CHALLENGE_SIZE_32, TOKEN_SIZE, PSA_SUCCESS +}, + +{"Test psa_initial_attestation_get_token_size with Challenge 48\n", + PSA_INITIAL_ATTEST_CHALLENGE_SIZE_48, PSA_INITIAL_ATTEST_CHALLENGE_SIZE_48, TOKEN_SIZE, PSA_SUCCESS +}, + +{"Test psa_initial_attestation_get_token_size with Challenge 64\n", + PSA_INITIAL_ATTEST_CHALLENGE_SIZE_64, PSA_INITIAL_ATTEST_CHALLENGE_SIZE_64, TOKEN_SIZE, PSA_SUCCESS +}, + +{"Test psa_initial_attestation_get_token_size with zero challenge size\n", + 0, 0, + TOKEN_SIZE, PSA_ATTEST_ERR_INVALID_INPUT +}, + +{"Test psa_initial_attestation_get_token_size with small challenge size\n", + PSA_INITIAL_ATTEST_CHALLENGE_SIZE_32-1, PSA_INITIAL_ATTEST_CHALLENGE_SIZE_32-1, + TOKEN_SIZE, PSA_ATTEST_ERR_INVALID_INPUT +}, + +{"Test psa_initial_attestation_get_token_size with invalid challenge size\n", + PSA_INITIAL_ATTEST_CHALLENGE_SIZE_32+1, PSA_INITIAL_ATTEST_CHALLENGE_SIZE_32+1, + TOKEN_SIZE, PSA_ATTEST_ERR_INVALID_INPUT +}, + +{"Test psa_initial_attestation_get_token_size with large challenge size\n", + MAX_CHALLENGE_SIZE+1, MAX_CHALLENGE_SIZE+1, + TOKEN_SIZE, PSA_ATTEST_ERR_INVALID_INPUT +}, +}; diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_attestation/test_a001/test_entry.c b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_attestation/test_a001/test_entry.c new file mode 100644 index 0000000..db253b8 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_attestation/test_a001/test_entry.c @@ -0,0 +1,52 @@ +/** @file + * Copyright (c) 2019, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ + +#include "val_interfaces.h" +#include "val_target.h" +#include "test_a001.h" + +#define TEST_NUM VAL_CREATE_TEST_ID(VAL_INITIAL_ATTESTATION_BASE, 1) +#define TEST_DESC "Testing initial attestation APIs\n" +TEST_PUBLISH(TEST_NUM, test_entry); +val_api_t *val = NULL; +psa_api_t *psa = NULL; + +void test_entry(val_api_t *val_api, psa_api_t *psa_api) +{ + int32_t status = VAL_STATUS_SUCCESS; + + val = val_api; + psa = psa_api; + + /* test init */ + val->test_init(TEST_NUM, TEST_DESC, TEST_FIELD(TEST_ISOLATION_L1, WD_HIGH_TIMEOUT)); + if (!IS_TEST_START(val->get_status())) + { + goto test_exit; + } + + /* Execute list of tests available in test[num]_attestation_list from Non-secure side*/ + status = val->execute_non_secure_tests(TEST_NUM, test_a001_attestation_list, FALSE); + + if (VAL_ERROR(status)) + { + goto test_exit; + } + +test_exit: + val->test_exit(); +} diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/psa_its_testlist.md b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/psa_its_testlist.md new file mode 100644 index 0000000..b466a7e --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/psa_its_testlist.md @@ -0,0 +1,30 @@ +# PSA Internal Trusted Storage Testcase checklist + +## Requirements for Storage Test Suite + +Following are the requirements of the Storage Test Suite.
+ +1. Unless described in this document, any behaviour that is defined as IMPLEMENTATION_DEFINED in PSA Storage API document is not verified in this document.
+2. Storage Test Cases use UID value starting from 1 onwards. These UID needs to be free for successfull test execution.
+3. UID values 1 and 2 are reserved as WRITE_ONCE UID.These UID can't be free from testcase. Make sure these are free.
+ + +| Test | Return Value | API Verified | Test Algorithm | UID Usage | +|-----------|--------------------------------------|------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| test_s001 | PSA_ITS_ERROR_UID_NOT_FOUND | psa_its_get
psa_its_get_info
psa_its_remove
| 1. Call get API with UID for which no UID/Data pair is created
2. Call get_info API for which no UID/Data pair is created
3. Call remove API for which no UID/Data pair is created
4. Set valid UID/Data pair with uid1
5. Set one more set of UID/Data pair, with different uid, than previous
6. Remove the uid of step 4.
7. Call get API for removed UID/data pair
8. Call get_info API for removed UID/Data pair
9. Call remove API for removed UID/Data pair
10. Set valid UID/Data pair
11. Call get API for different uid , then created
12. Call get_info API for different uid, then created
13. Call remove API for different uid, then created
14. Remove the created UID/Data pair.
15. Remove the stray uid.
| UID value used are 5,6,7 | +| test_s002 | PSA_ITS_ERROR_WRITE_ONCE | psa_its_set
psa_its_remove
| 1. Set valid UID/data value pair , with create flag value none.2. Call get and get_info API to validate the data, attributes associated with data
3. Call set API again with same uid and create flag PSA_PS_WRITE_ONCE_FLAG
4. Call get and get_info API to validate the data, attributes associated with data is not changed after second set operation
5. try to remove the UID/data pair.
6. Create new UID/data value pair, with create flag PSA_PS_WRITE_ONCE_FLAG
7. Try to remove the created UID.
8. Call get and get_info API to validate the data, attributes associated with data
9. Again call SET with same UID , create flag PSA_PS_WRITE_ONCE_FLAG but different data length
10. Try to remove the UID, PSA_ITS_ERROR_WRITE_ONCE error should be returned
11. Call get and get_info API to validate the data, attributes associated with data
| UID value used are 1 and 2 | +| test_s003 | PSA_ITS_ERROR_INSUFFICIENT_SPACE | psa_its_set
| 1. Create UID/data pairs, with data_len 256 bytes. Do this with incrementing uid values till we have INSUFFICENT_SPACE.
2. Remove all the UID/data pairs created.
3. Repeat the steps once more, to check all previous uid are removed successfully
| UID value starts from 5 and keep on incrementing till all space is exhausted | +| test_s004 | PSA_ITS_SUCCESS | psa_its_set
psa_its_get
psa_its_get_info
psa_its_remove
| 1. Set a valid uid/data pair
2. Validate the data using get api
3. Change the data length to half of previous.
4. Call GET api with original data length , error should be returned and also the return buffer should be empty
5. Call GET api with correct data_len and validate the data received.
6. Check old data cannot be accessed.
7. Call REMOVE api to delete the UID/data pair
| UID value used is 5 | +| test_s005 | PSA_ITS_SUCCESS | psa_its_set
psa_its_get
psa_its_get_info
psa_its_remove
| 1. Set valid UID/data pair with varying uid and data_len
2. Call GET api and validate the set data
3. Call GET info api and validate the data attributes
4. Call REMOVE api to delete the UID/data pair
| UID value used are 4 | +| test_s006 | PSA_ITS_ERROR_FLAGS_NOT_SUPPORTED | psa_its_set
| 1. Call the SET_INFO with minimum flag value to max flag value
2. Call GET_INFO api and validate the flag value
3. Remove the uid/data pair
| UID value used is 5 | +| test_s007 | PSA_ITS_ERROR_INCORRECT_SIZE | psa_its_set
| 1. Create valid uid/data pair.
2. Increase the length of storage.
3. Try to access the old length using get api.
4. Try to access with valid length less than stored size.
5. Decrease the length of storage.
6. Try to access the old length.
7. Remove the uid
| UID value used is 5 | +| test_s008 | PSA_ITS_ERROR_OFFSET_INVALID | psa_its_get
| 1. Set valid UID/data pair
2. Call GET api with valid offset and offset + data_len equal to stored data size.
3. Call GET api with valid offset and offset + data_len less than stored data size.
4. Call get api with invalid offset.
5. Call get api with zero offset , but data len greater than data size.
6. Remove the uid.
| UID value used is 5 | +| test_s009 | PSA_ITS_SUCCESS | psa_its_get
psa_its_set
psa_its_get_info
| 1. Call the SET API with NULL pointer and data_len zero
2. Validate using get_info api storage should be present.
3. Call get API with NULL pointer.
4. Remove the UID.
5. Call get_info API to validate storage is removed.
6. Set storage entity with valid write_buffer , but length zero.
7. Call get_info API to validate storage attributes.
8. Call get_info api with NULL pointer and valid uid.
9. Remove the uid
| UID value used is 5
| +| test_s010 | PSA_ITS_ERROR_STORAGE_FAILURE
| psa_its_set
| 1. Call the SET API with UID value 0.
2. Check that storage creation fails.
| UID value used is 0
| + +## License +Arm PSA test suite is distributed under Apache v2.0 License. + +-------------- + +*Copyright (c) 2019, Arm Limited and Contributors. All rights reserved.* diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s001/main.c b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s001/main.c new file mode 100644 index 0000000..2ab8343 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s001/main.c @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2020, Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "val_interfaces.h" +#include "pal_mbed_os_intf.h" + +#if !defined(MBED_CONF_RTOS_PRESENT) +#error [NOT_SUPPORTED] PSA compliance its test cases require RTOS to run +#else + +#ifdef ITS_TEST +void test_entry_s001(val_api_t *val_api, psa_api_t *psa_api); +#elif PS_TEST +void test_entry_p001(val_api_t *val_api, psa_api_t *psa_api); +#endif + +int main(void) +{ +#ifdef ITS_TEST + test_start(test_entry_s001, COMPLIANCE_TEST_STORAGE); +#elif PS_TEST + test_start(test_entry_p001, COMPLIANCE_TEST_STORAGE); +#endif +} +#endif // !defined(MBED_CONF_RTOS_PRESENT) diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s001/test_entry.c b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s001/test_entry.c new file mode 100644 index 0000000..8b8aed9 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s001/test_entry.c @@ -0,0 +1,53 @@ +/** @file + * Copyright (c) 2019, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ + +#include "val_interfaces.h" +#include "val_target.h" +#include "test_s001.h" + +#define TEST_NUM VAL_CREATE_TEST_ID(VAL_STORAGE_BASE, 1) +#define TEST_DESC "UID not found check\n" + +TEST_PUBLISH(TEST_NUM, test_entry); +val_api_t *val = NULL; +psa_api_t *psa = NULL; + +void test_entry(val_api_t *val_api, psa_api_t *psa_api) +{ + int32_t status = VAL_STATUS_SUCCESS; + + val = val_api; + psa = psa_api; + + /* test init */ + val->test_init(TEST_NUM, TEST_DESC, TEST_FIELD(TEST_ISOLATION_L1, WD_HIGH_TIMEOUT)); + if (!IS_TEST_START(val->get_status())) + { + goto test_exit; + } + + /* Execute list of tests available in test[num]_secure_storage_list from Non-secure side*/ + status = val->execute_non_secure_tests(TEST_NUM, test_s001_sst_list, FALSE); + + if (VAL_ERROR(status)) + { + goto test_exit; + } + +test_exit: + val->test_exit(); +} diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s001/test_its_data.h b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s001/test_its_data.h new file mode 100644 index 0000000..af95d04 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s001/test_its_data.h @@ -0,0 +1,81 @@ +/** @file + * Copyright (c) 2019, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ +#ifndef _TEST_S001_ITS_DATA_TESTS_H_ +#define _TEST_S001_ITS_DATA_TESTS_H_ + +#include "val_internal_trusted_storage.h" + +#define SST_FUNCTION val->its_function +#define psa_sst_uid_t psa_its_uid_t + +typedef struct { + enum its_function_code api; + psa_its_status_t status; +} test_data; + +static struct psa_its_info_t info; +static const test_data s001_data[] = { +{ + 0, 0 /* Unused Index0 */ +}, +{ + VAL_ITS_GET, PSA_ITS_ERROR_UID_NOT_FOUND /* Call the get API when no UID is set */ +}, +{ + VAL_ITS_GET_INFO, PSA_ITS_ERROR_UID_NOT_FOUND /* Call the get_info API when no UID is set */ +}, +{ + VAL_ITS_REMOVE, PSA_ITS_ERROR_UID_NOT_FOUND /* Call the remove API when no UID is set */ +}, +{ + VAL_ITS_SET, PSA_ITS_SUCCESS /* Create a valid storage entity with UID1 */ +}, +{ + VAL_ITS_SET, PSA_ITS_SUCCESS /* Create a valid storage entity with UID2 */ +}, +{ + VAL_ITS_REMOVE, PSA_ITS_SUCCESS /* Remove UID1 */ +}, +{ + VAL_ITS_GET, PSA_ITS_ERROR_UID_NOT_FOUND /* Call get API for UID1 */ +}, +{ + VAL_ITS_GET_INFO, PSA_ITS_ERROR_UID_NOT_FOUND /* Call get_info API for UID1 */ +}, +{ + VAL_ITS_REMOVE, PSA_ITS_ERROR_UID_NOT_FOUND /* Call remove API for UID1 */ +}, +{ + VAL_ITS_SET, PSA_ITS_SUCCESS /* Create a valid storage entity again with UID1 */ +}, +{ + VAL_ITS_GET, PSA_ITS_ERROR_UID_NOT_FOUND /* Call get API for UID not same as UID1 or UID2 */ +}, +{ + VAL_ITS_GET_INFO, PSA_ITS_ERROR_UID_NOT_FOUND /* Call get_info for UID not same as UID1 or UID2 */ +}, +{ + VAL_ITS_REMOVE, PSA_ITS_ERROR_UID_NOT_FOUND /* Call remove API for UID not same as UID1 or UID2 */ +}, +{ + VAL_ITS_REMOVE, PSA_ITS_SUCCESS /* Remove UID1 */ +}, +{ + VAL_ITS_REMOVE, PSA_ITS_SUCCESS /* Remove UID2 */ +}, +}; +#endif /* _TEST_S001_ITS_DATA_TESTS_H_ */ diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s001/test_ps_data.h b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s001/test_ps_data.h new file mode 100644 index 0000000..2013058 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s001/test_ps_data.h @@ -0,0 +1,81 @@ +/** @file + * Copyright (c) 2019, Arm Limited or ps affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ +#ifndef _TEST_S001_PS_DATA_TESTS_H_ +#define _TEST_S001_PS_DATA_TESTS_H_ + +#include "val_protected_storage.h" + +#define SST_FUNCTION val->ps_function +#define psa_sst_uid_t psa_ps_uid_t + +typedef struct { + enum ps_function_code api; + psa_ps_status_t status; +} test_data; + +static struct psa_ps_info_t info; +static const test_data s001_data[] = { +{ + 0, 0 /* This is dummy for index0 */ +}, +{ + VAL_PS_GET, PSA_PS_ERROR_UID_NOT_FOUND /* Call the get API when no UID is set */ +}, +{ + VAL_PS_GET_INFO, PSA_PS_ERROR_UID_NOT_FOUND /* Call the get_info API when no UID is set */ +}, +{ + VAL_PS_REMOVE, PSA_PS_ERROR_UID_NOT_FOUND /* Call the remove API when no UID is set */ +}, +{ + VAL_PS_SET, PSA_PS_SUCCESS /* Create a valid storage entity with UID1 */ +}, +{ + VAL_PS_SET, PSA_PS_SUCCESS /* Create a valid storage entity with UID2 */ +}, +{ + VAL_PS_REMOVE, PSA_PS_SUCCESS /* Remove UID1 */ +}, +{ + VAL_PS_GET, PSA_PS_ERROR_UID_NOT_FOUND /* Call get API for UID1 */ +}, +{ + VAL_PS_GET_INFO, PSA_PS_ERROR_UID_NOT_FOUND /* Call get_info API for UID1 */ +}, +{ + VAL_PS_REMOVE, PSA_PS_ERROR_UID_NOT_FOUND /* Call remove API for UID1 */ +}, +{ + VAL_PS_SET, PSA_PS_SUCCESS /* Create a valid storage entity again with UID1 */ +}, +{ + VAL_PS_GET, PSA_PS_ERROR_UID_NOT_FOUND /* Call get API for UID not same as UID1 or UID2 */ +}, +{ + VAL_PS_GET_INFO, PSA_PS_ERROR_UID_NOT_FOUND /* Call get_info for UID not same as UID1 or UID2 */ +}, +{ + VAL_PS_REMOVE, PSA_PS_ERROR_UID_NOT_FOUND /* Call remove API for UID not same as UID1 or UID2 */ +}, +{ + VAL_PS_REMOVE, PSA_PS_SUCCESS /* Remove UID1 */ +}, +{ + VAL_PS_REMOVE, PSA_PS_SUCCESS /* Remove UID2 */ +}, +}; +#endif /* _TEST_S001_PS_DATA_TESTS_H_ */ diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s001/test_s001.c b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s001/test_s001.c new file mode 100644 index 0000000..5e9c26f --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s001/test_s001.c @@ -0,0 +1,170 @@ +/** @file + * Copyright (c) 2019, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ + +#include "val_interfaces.h" +#include "val_target.h" +#include "test_s001.h" +#ifdef ITS_TEST +#include "test_its_data.h" +#elif PS_TEST +#include "test_ps_data.h" +#endif + +#define TEST_BUFF_SIZE 16 + +client_test_t test_s001_sst_list[] = { + NULL, + psa_sst_uid_not_found, + NULL, +}; + +static uint8_t write_buff[TEST_BUFF_SIZE] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F}; +static uint8_t read_buff[TEST_BUFF_SIZE] = {0}; + +static int32_t sst_calls_without_set_call(psa_sst_uid_t p_uid) +{ + uint32_t status; + + /* get() without using set() before */ + val->print(PRINT_TEST, "[Check 1] Call get API for UID %d which is not set\n", p_uid); + status = SST_FUNCTION(s001_data[1].api, p_uid, 0, TEST_BUFF_SIZE, read_buff); + TEST_ASSERT_EQUAL(status,s001_data[1].status,TEST_CHECKPOINT_NUM(1)); + + /* get_info() without using set() before */ + val->print(PRINT_TEST, "[Check 2] Call get_info API for UID %d which is not set\n", p_uid); + status = SST_FUNCTION(s001_data[2].api, p_uid, &info); + TEST_ASSERT_EQUAL(status, s001_data[2].status, TEST_CHECKPOINT_NUM(2)); + + /* remove() without using set() before */ + val->print(PRINT_TEST, "[Check 3] Call remove API for UID %d which is not set\n", p_uid); + status = SST_FUNCTION(s001_data[3].api, p_uid); + TEST_ASSERT_EQUAL(status, s001_data[3].status, TEST_CHECKPOINT_NUM(3)); + + return VAL_STATUS_SUCCESS; +} + +static int32_t sst_set_and_remove(psa_sst_uid_t p_uid) +{ + uint32_t status; + + /* set() a UID1 */ + status = SST_FUNCTION(s001_data[4].api, p_uid, TEST_BUFF_SIZE, write_buff, 0); + TEST_ASSERT_EQUAL(status, s001_data[4].status, TEST_CHECKPOINT_NUM(4)); + + /* Also set() with a different UID */ + status = SST_FUNCTION(s001_data[5].api, p_uid + 1, TEST_BUFF_SIZE, write_buff, 0); + TEST_ASSERT_EQUAL(status, s001_data[5].status, TEST_CHECKPOINT_NUM(5)); + + /* remove() UID1 */ + status = SST_FUNCTION(s001_data[6].api, p_uid); + TEST_ASSERT_EQUAL(status, s001_data[6].status, TEST_CHECKPOINT_NUM(6)); + + return VAL_STATUS_SUCCESS; +} + +static int32_t sst_calls_after_uid_remove(psa_sst_uid_t p_uid) +{ + uint32_t status; + + /* get() for UID which is removed */ + val->print(PRINT_TEST, "[Check 4] Call get API for UID %d which is removed\n", p_uid); + status = SST_FUNCTION(s001_data[7].api, p_uid, 0, TEST_BUFF_SIZE, read_buff); + TEST_ASSERT_EQUAL(status, s001_data[7].status, TEST_CHECKPOINT_NUM(7)); + + /* get_info() for UID which is removed */ + val->print(PRINT_TEST, "[Check 5] Call get_info API for UID %d which is removed\n", p_uid); + status = SST_FUNCTION(s001_data[8].api, p_uid, &info); + TEST_ASSERT_EQUAL(status, s001_data[8].status, TEST_CHECKPOINT_NUM(8)); + + /* remove() for UID which is removed */ + val->print(PRINT_TEST, "[Check 6] Call remove API for UID %d which is removed\n", p_uid); + status = SST_FUNCTION(s001_data[9].api, p_uid); + TEST_ASSERT_EQUAL(status, s001_data[9].status, TEST_CHECKPOINT_NUM(9)); + + return VAL_STATUS_SUCCESS; +} + +static int32_t sst_calls_with_different_uid(psa_sst_uid_t p_uid) +{ + uint32_t status; + + /* set() a UID */ + val->print(PRINT_TEST, "Set storage for UID %d\n", p_uid); + status = SST_FUNCTION(s001_data[10].api, p_uid, TEST_BUFF_SIZE, write_buff, 0); + TEST_ASSERT_EQUAL(status, s001_data[10].status, TEST_CHECKPOINT_NUM(10)); + + /* get() for different UID then set UID */ + val->print(PRINT_TEST, "[Check 7] Call get API for different UID %d\n", p_uid); + status = SST_FUNCTION(s001_data[11].api, p_uid-1, 0, TEST_BUFF_SIZE - 1, read_buff); + TEST_ASSERT_EQUAL(status, s001_data[11].status, TEST_CHECKPOINT_NUM(11)); + + /* get_info() for different UID then set UID */ + val->print(PRINT_TEST, "[Check 8] Call get_info API for different UID %d\n", p_uid); + status = SST_FUNCTION(s001_data[12].api, p_uid-1, &info); + TEST_ASSERT_EQUAL(status, s001_data[12].status, TEST_CHECKPOINT_NUM(12)); + + /* remove() for different UID then set UID */ + val->print(PRINT_TEST, "[Check 9] Call remove API for different UID %d\n", p_uid); + status = SST_FUNCTION(s001_data[13].api, p_uid-1); + TEST_ASSERT_EQUAL(status, s001_data[13].status, TEST_CHECKPOINT_NUM(13)); + + /* remove() the set UID */ + status = SST_FUNCTION(s001_data[14].api, p_uid); + TEST_ASSERT_EQUAL(status, s001_data[14].status, TEST_CHECKPOINT_NUM(14)); + + return VAL_STATUS_SUCCESS; +} + +static int32_t sst_remove_stray_uid(psa_sst_uid_t p_uid) +{ + uint32_t status; + + /* Remove UID + 1 */ + status = SST_FUNCTION(s001_data[15].api, p_uid); + TEST_ASSERT_EQUAL(status, s001_data[15].status, TEST_CHECKPOINT_NUM(15)); + + return VAL_STATUS_SUCCESS; +} + +int32_t psa_sst_uid_not_found(caller_security_t caller) +{ + int32_t test_status; + psa_sst_uid_t uid = UID_BASE_VALUE + 6; + + test_status = sst_calls_without_set_call(uid); + if (test_status != VAL_STATUS_SUCCESS) + return test_status; + + test_status = sst_set_and_remove(uid); + if (test_status != VAL_STATUS_SUCCESS) + return test_status; + + test_status = sst_calls_after_uid_remove(uid); + if (test_status != VAL_STATUS_SUCCESS) + return test_status; + + test_status = sst_calls_with_different_uid(uid); + if (test_status != VAL_STATUS_SUCCESS) + return test_status; + + test_status = sst_remove_stray_uid(uid + 1); + if (test_status != VAL_STATUS_SUCCESS) + return test_status; + + return VAL_STATUS_SUCCESS; +} diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s001/test_s001.h b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s001/test_s001.h new file mode 100644 index 0000000..08e5691 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s001/test_s001.h @@ -0,0 +1,35 @@ +/** @file + * Copyright (c) 2019, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ +#ifndef _TEST_S001_CLIENT_TESTS_H_ +#define _TEST_S001_CLIENT_TESTS_H_ + +#ifdef ITS_TEST +#define VAL_STORAGE_BASE VAL_INTERNAL_TRUSTED_STORAGE_BASE +#define test_entry CONCAT(test_entry_, s001) +#elif PS_TEST +#define VAL_STORAGE_BASE VAL_PROTECTED_STORAGE_BASE +#define test_entry CONCAT(test_entry_, p001) +#endif +#define val CONCAT(val,test_entry) +#define psa CONCAT(psa,test_entry) + +extern val_api_t *val; +extern psa_api_t *psa; +extern client_test_t test_s001_sst_list[]; + +int32_t psa_sst_uid_not_found(caller_security_t caller); +#endif /* _TEST_S001_CLIENT_TESTS_H_ */ diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s002/main.c b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s002/main.c new file mode 100644 index 0000000..46729ac --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s002/main.c @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2020, Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "val_interfaces.h" +#include "pal_mbed_os_intf.h" +#include "lifecycle.h" +#if !defined(MBED_CONF_RTOS_PRESENT) +#error [NOT_SUPPORTED] PSA compliance its test cases require RTOS to run +#else + +#ifdef ITS_TEST +void test_entry_s002(val_api_t *val_api, psa_api_t *psa_api); +#elif PS_TEST +void test_entry_p002(val_api_t *val_api, psa_api_t *psa_api); +#endif + +int main(void) +{ +#ifdef ITS_TEST + test_start(test_entry_s002, COMPLIANCE_TEST_STORAGE); +#elif PS_TEST + test_start(test_entry_p002, COMPLIANCE_TEST_STORAGE); +#endif +} +#endif // !defined(MBED_CONF_RTOS_PRESENT) diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s002/test_entry.c b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s002/test_entry.c new file mode 100644 index 0000000..538a41f --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s002/test_entry.c @@ -0,0 +1,53 @@ +/** @file + * Copyright (c) 2019, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ + +#include "val_interfaces.h" +#include "val_target.h" +#include "test_s002.h" + +#define TEST_NUM VAL_CREATE_TEST_ID(VAL_STORAGE_BASE, 2) +#define TEST_DESC "Write once error check\n" + +TEST_PUBLISH(TEST_NUM, test_entry); +val_api_t *val = NULL; +psa_api_t *psa = NULL; + +void test_entry(val_api_t *val_api, psa_api_t *psa_api) +{ + int32_t status = VAL_STATUS_SUCCESS; + + val = val_api; + psa = psa_api; + + /* test init */ + val->test_init(TEST_NUM, TEST_DESC, TEST_FIELD(TEST_ISOLATION_L1, WD_HIGH_TIMEOUT)); + if (!IS_TEST_START(val->get_status())) + { + goto test_exit; + } + + /* Execute list of tests available in test[num]_secure_storage_list from Non-secure side*/ + status = val->execute_non_secure_tests(TEST_NUM, test_s002_sst_list, FALSE); + + if (VAL_ERROR(status)) + { + goto test_exit; + } + +test_exit: + val->test_exit(); +} diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s002/test_its_data.h b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s002/test_its_data.h new file mode 100644 index 0000000..303b25f --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s002/test_its_data.h @@ -0,0 +1,134 @@ +/** @file + * Copyright (c) 2019, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ +#ifndef _TEST_S002_ITS_DATA_TESTS_H_ +#define _TEST_S002_ITS_DATA_TESTS_H_ + +#include "val_internal_trusted_storage.h" + +#define SST_FUNCTION val->its_function +#define PSA_SST_FLAG_WRITE_ONCE PSA_ITS_FLAG_WRITE_ONCE +#define psa_sst_uid_t psa_its_uid_t + +typedef struct { + enum its_function_code api; + psa_its_status_t status; +} test_data; + +static struct psa_its_info_t orig_info; +static struct psa_its_info_t new_info; +static const test_data s002_data[] = { +{ + 0, 0 /* This is dummy for index0 */ +}, +{ + VAL_ITS_SET, PSA_ITS_SUCCESS /* Create a valid storage with create flag value 0 */ +}, +{ + VAL_ITS_GET_INFO, PSA_ITS_SUCCESS /* Call the get_info API to validate the attributes */ +}, +{ + 0, 0 /* Index not used as check for get info size */ +}, +{ + 0, 0 /* Index not used as check for get info flag */ +}, +{ + VAL_ITS_GET, PSA_ITS_SUCCESS /* Validate the data using get API */ +}, +{ + 0, 0 /* Index not used */ +}, +{ + VAL_ITS_SET, PSA_ITS_SUCCESS /* Change the flag to WRITE_ONCE using set API */ +}, +{ + VAL_ITS_GET_INFO, PSA_ITS_SUCCESS /* Call the get_info API to validate the flag change */ +}, +{ + 0, 0 /* Index not used as check for get info size */ +}, +{ + 0, 0 /* Index not used as check for get info flag */ +}, +{ + VAL_ITS_GET, PSA_ITS_SUCCESS /* Validate the data using get API after flag change */ +}, +{ + 0, 0 /* Index not used */ +}, +{ + VAL_ITS_REMOVE, PSA_ITS_ERROR_WRITE_ONCE /* Storage should not be removed after WRITE_ONCE flag */ +}, +{ + VAL_ITS_SET, PSA_ITS_SUCCESS /* Create a storage with different UID and flag value WRITE_ONCE */ +}, +{ + VAL_ITS_REMOVE, PSA_ITS_ERROR_WRITE_ONCE /* Storage should not be removed */ +}, +{ + VAL_ITS_GET, PSA_ITS_SUCCESS /* Validate the data using get API after flag change */ +}, +{ + 0, 0 /* Index not used */ +}, +{ + VAL_ITS_GET_INFO, PSA_ITS_SUCCESS /* Call the get_info API to validate the flag change */ +}, +{ + 0, 0 /* Index not used as check for get info size */ +}, +{ + 0, 0 /* Index not used as check for get info flag */ +}, +{ + VAL_ITS_SET, PSA_ITS_ERROR_WRITE_ONCE /* Try to set different size for same UID and flag value */ +}, +{ + VAL_ITS_REMOVE, PSA_ITS_ERROR_WRITE_ONCE /* Storage should not be removed */ +}, +{ + VAL_ITS_GET_INFO, PSA_ITS_SUCCESS /* Call the get_info API to validate the flag change */ +}, +{ + 0, 0 /* Index not used as check for get info size */ +}, +{ + 0, 0 /* Index not used as check for get info flag */ +}, +{ + VAL_ITS_GET, PSA_ITS_SUCCESS /* Validate the data using get API after flag change */ +}, +{ + 0, 0 /* Index not used */ +}, +{ + VAL_ITS_SET, PSA_ITS_ERROR_WRITE_ONCE /* Setting flag to zero for UID should fail */ +}, +{ + VAL_ITS_REMOVE, PSA_ITS_ERROR_WRITE_ONCE /* Storage should not be removed */ +}, +{ + VAL_ITS_GET_INFO, PSA_ITS_SUCCESS /* Check that the WRITE_ONCE flag is preserved */ +}, +{ + 0, 0 /* Index not used as check for get info size */ +}, +{ + 0, 0 /* Index not used as check for get info flag */ +}, +}; +#endif /* _TEST_S002_ITS_DATA_TESTS_H_ */ diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s002/test_ps_data.h b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s002/test_ps_data.h new file mode 100644 index 0000000..19e88b7 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s002/test_ps_data.h @@ -0,0 +1,134 @@ +/** @file + * Copyright (c) 2019, Arm Limited or ps affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ +#ifndef _TEST_S002_PS_DATA_TESTS_H_ +#define _TEST_S002_PS_DATA_TESTS_H_ + +#include "val_protected_storage.h" + +#define SST_FUNCTION val->ps_function +#define PSA_SST_FLAG_WRITE_ONCE PSA_PS_FLAG_WRITE_ONCE +#define psa_sst_uid_t psa_ps_uid_t + +typedef struct { + enum ps_function_code api; + psa_ps_status_t status; +} test_data; + +static struct psa_ps_info_t orig_info; +static struct psa_ps_info_t new_info; +static const test_data s002_data[] = { +{ + 0, 0 /* This is dummy for index0 */ +}, +{ + VAL_PS_SET, PSA_PS_SUCCESS /* Create a valid storage with create flag value 0 */ +}, +{ + VAL_PS_GET_INFO, PSA_PS_SUCCESS /* Call the get_info API to validate the attributes */ +}, +{ + 0, 0 /* Index not used as check for get info size */ +}, +{ + 0, 0 /* Index not used as check for get info flag */ +}, +{ + VAL_PS_GET, PSA_PS_SUCCESS /* Validate the data using get API */ +}, +{ + 0, 0 /* Index not used */ +}, +{ + VAL_PS_SET, PSA_PS_SUCCESS /* Change the flag to WRITE_ONCE using set API */ +}, +{ + VAL_PS_GET_INFO, PSA_PS_SUCCESS /* Call the get_info API to validate the flag change */ +}, +{ + 0, 0 /* Index not used as check for get info size */ +}, +{ + 0, 0 /* Index not used as check for get info flag */ +}, +{ + VAL_PS_GET, PSA_PS_SUCCESS /* Validate the data using get API after flag change */ +}, +{ + 0, 0 /* Index not used */ +}, +{ + VAL_PS_REMOVE, PSA_PS_ERROR_WRITE_ONCE /* Storage should not be removed after WRITE_ONCE flag */ +}, +{ + VAL_PS_SET, PSA_PS_SUCCESS /* Create storage with different UID and flag value WRITE_ONCE */ +}, +{ + VAL_PS_REMOVE, PSA_PS_ERROR_WRITE_ONCE /* Storage should not be removed */ +}, +{ + VAL_PS_GET, PSA_PS_SUCCESS /* Validate the data using get API after flag change */ +}, +{ + 0, 0 /* Index not used */ +}, +{ + VAL_PS_GET_INFO, PSA_PS_SUCCESS /* Call the get_info API to validate the flag change */ +}, +{ + 0, 0 /* Index not used as check for get info size */ +}, +{ + 0, 0 /* Index not used as check for get info flag */ +}, +{ + VAL_PS_SET, PSA_PS_ERROR_WRITE_ONCE /* Try to set different size for same UID and flag value */ +}, +{ + VAL_PS_REMOVE, PSA_PS_ERROR_WRITE_ONCE /* Storage should not be removed */ +}, +{ + VAL_PS_GET_INFO, PSA_PS_SUCCESS /* Call the get_info API to validate the flag change */ +}, +{ + 0, 0 /* Index not used as check for get info size */ +}, +{ + 0, 0 /* Index not used as check for get info flag */ +}, +{ + VAL_PS_GET, PSA_PS_SUCCESS /* Validate the data using get API after flag change */ +}, +{ + 0, 0 /* Index not used */ +}, +{ + VAL_PS_SET, PSA_PS_ERROR_WRITE_ONCE /* Setting flag to zero for UID should fail */ +}, +{ + VAL_PS_REMOVE, PSA_PS_ERROR_WRITE_ONCE /* Storage should not be removed */ +}, +{ + VAL_PS_GET_INFO, PSA_PS_SUCCESS /* Check that the WRITE_ONCE flag is preserved */ +}, +{ + 0, 0 /* Index not used as check for get info size */ +}, +{ + 0, 0 /* Index not used as check for get info flag */ +}, +}; +#endif /* _TEST_S002_PS_DATA_TESTS_H_ */ diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s002/test_s002.c b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s002/test_s002.c new file mode 100644 index 0000000..d46ace1 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s002/test_s002.c @@ -0,0 +1,161 @@ +/** @file + * Copyright (c) 2019, Arm Limited or sst affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ + +#include "val_interfaces.h" +#include "val_target.h" +#include "test_s002.h" +#ifdef ITS_TEST +#include "test_its_data.h" +#elif PS_TEST +#include "test_ps_data.h" +#endif + +#define UID_WRITE_ONCE_1 UID_BASE_VALUE + 1 +#define UID_WRITE_ONCE_2 UID_BASE_VALUE + 2 +#define TEST_BUFF_SIZE 16 + +client_test_t test_s002_sst_list[] = { + NULL, + psa_sst_update_write_once_flag_after_create, + psa_sst_create_with_write_once_flag, + NULL, +}; + +int32_t psa_sst_update_write_once_flag_after_create(caller_security_t caller) +{ + uint32_t status; + psa_sst_uid_t uid = UID_WRITE_ONCE_1; + uint8_t write_buff[TEST_BUFF_SIZE/2] = {0xDE, 0xAD, 0xBE, 0xEF, 0xCA, 0xFE, 0xBA, 0xBE}; + uint8_t read_buff[TEST_BUFF_SIZE/2] = {0}; + uint8_t write_buff_new[TEST_BUFF_SIZE/4] = {0xFF, 0xFF, 0xFF, 0xFF}; + + /* set() data without a WRITE_ONCE flag */ + status = SST_FUNCTION(s002_data[1].api, uid, TEST_BUFF_SIZE/2, write_buff, 0); + TEST_ASSERT_EQUAL(status, s002_data[1].status, TEST_CHECKPOINT_NUM(1)); + + /* Check that get_info() returns correct attributes; also store for reference for later */ + status = SST_FUNCTION(s002_data[2].api, uid, &orig_info); + TEST_ASSERT_EQUAL(status, s002_data[2].status, TEST_CHECKPOINT_NUM(2)); + TEST_ASSERT_EQUAL(orig_info.size, TEST_BUFF_SIZE/2, TEST_CHECKPOINT_NUM(3)); + TEST_ASSERT_EQUAL(orig_info.flags, 0, TEST_CHECKPOINT_NUM(4)); + + /* Check for data consistency using get() */ + status = SST_FUNCTION(s002_data[5].api, uid, 0, TEST_BUFF_SIZE/2, read_buff); + TEST_ASSERT_EQUAL(status, s002_data[5].status, TEST_CHECKPOINT_NUM(5)); + TEST_ASSERT_MEMCMP(write_buff, read_buff, TEST_BUFF_SIZE/2, TEST_CHECKPOINT_NUM(6)); + + /* set() with WRITE_ONCE_FLAG */ + val->print(PRINT_TEST, "[Check 1] Update the flag of UID %d with WRITE_ONCE flag\n", uid); + status = SST_FUNCTION(s002_data[7].api, uid, TEST_BUFF_SIZE/4, write_buff_new, + PSA_SST_FLAG_WRITE_ONCE); + TEST_ASSERT_EQUAL(status, s002_data[7].status, TEST_CHECKPOINT_NUM(7)); + + /* Check that info is updated, after new set */ + status = SST_FUNCTION(s002_data[8].api, uid, &new_info); + TEST_ASSERT_EQUAL(status, s002_data[8].status, TEST_CHECKPOINT_NUM(8)); + TEST_ASSERT_EQUAL(new_info.size, new_info.size, TEST_CHECKPOINT_NUM(9)); + TEST_ASSERT_EQUAL(new_info.flags, new_info.flags, TEST_CHECKPOINT_NUM(10)); + + /* Check that data contents are preserved which were written with WRITE_ONCE_FLAG originally */ + status = SST_FUNCTION(s002_data[11].api, uid, 0, TEST_BUFF_SIZE/4, read_buff); + TEST_ASSERT_EQUAL(status, s002_data[11].status, TEST_CHECKPOINT_NUM(11)); + TEST_ASSERT_MEMCMP(write_buff_new, read_buff, TEST_BUFF_SIZE/4, TEST_CHECKPOINT_NUM(12)); + + /* remove() the UID */ + val->print(PRINT_TEST, "[Check 2] Try to remove the UID %d having WRITE_ONCE flag\n", uid); + status = SST_FUNCTION(s002_data[13].api, uid); + TEST_ASSERT_EQUAL(status, s002_data[13].status, TEST_CHECKPOINT_NUM(13)); + + return VAL_STATUS_SUCCESS; +} + + +int32_t psa_sst_create_with_write_once_flag(caller_security_t caller) +{ + uint32_t status; + psa_sst_uid_t uid = UID_WRITE_ONCE_2; + uint8_t write_buff[TEST_BUFF_SIZE] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F}; + uint8_t read_buff[TEST_BUFF_SIZE] = {0}; + uint8_t write_buff_new[TEST_BUFF_SIZE + 1] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF}; + + /* Set data for a UID using WRITE_ONCE flag */ + val->print(PRINT_TEST, "[Check 3] Create a new UID %d with WRITE_ONCE flag\n", uid); + status = SST_FUNCTION(s002_data[14].api, uid, TEST_BUFF_SIZE, write_buff, + PSA_SST_FLAG_WRITE_ONCE); + TEST_ASSERT_EQUAL(status, s002_data[14].status, TEST_CHECKPOINT_NUM(14)); + + /* Check that remove() fails with PSA_SST_ERROR_WRITE_ONCE */ + val->print(PRINT_TEST, "[Check 4] Try to remove the UID %d having WRITE_ONCE flag\n", uid); + status = SST_FUNCTION(s002_data[15].api, uid); + TEST_ASSERT_EQUAL(status, s002_data[15].status, TEST_CHECKPOINT_NUM(15)); + + /* Check data consistency using get()*/ + status = SST_FUNCTION(s002_data[16].api, uid, 0, TEST_BUFF_SIZE, read_buff); + TEST_ASSERT_EQUAL(status, s002_data[16].status, TEST_CHECKPOINT_NUM(16)); + TEST_ASSERT_MEMCMP(write_buff, read_buff, TEST_BUFF_SIZE, TEST_CHECKPOINT_NUM(17)); + + /* Check that info values is as expected */ + status = SST_FUNCTION(s002_data[18].api, uid, &orig_info); + TEST_ASSERT_EQUAL(status, s002_data[18].status, TEST_CHECKPOINT_NUM(18)); + TEST_ASSERT_EQUAL(orig_info.size, TEST_BUFF_SIZE, TEST_CHECKPOINT_NUM(19)); + TEST_ASSERT_EQUAL(orig_info.flags, PSA_SST_FLAG_WRITE_ONCE, TEST_CHECKPOINT_NUM(20)); + + /* Try to overwrite using set() with same UID as used before with WRITE_ONCE_FLAG */ + val->print(PRINT_TEST, "[Check 5] Try to change the length of write_once UID %d\n", uid); + status = SST_FUNCTION(s002_data[21].api, uid, (TEST_BUFF_SIZE + 1), write_buff_new, + PSA_SST_FLAG_WRITE_ONCE); + TEST_ASSERT_EQUAL(status, s002_data[21].status, TEST_CHECKPOINT_NUM(21)); + + /* Check that remove() still fails with PSA_SST_ERROR_WRITE_ONCE */ + val->print(PRINT_TEST, "[Check 6] Check UID removal still fails\n", 0); + status = SST_FUNCTION(s002_data[22].api, uid); + TEST_ASSERT_EQUAL(status, s002_data[22].status, TEST_CHECKPOINT_NUM(22)); + + /* Check that info is preserved */ + status = SST_FUNCTION(s002_data[23].api, uid, &new_info); + TEST_ASSERT_EQUAL(status, s002_data[23].status, TEST_CHECKPOINT_NUM(23)); + TEST_ASSERT_EQUAL(new_info.size, orig_info.size, TEST_CHECKPOINT_NUM(24)); + TEST_ASSERT_EQUAL(new_info.flags, orig_info.flags, TEST_CHECKPOINT_NUM(25)); + + /* Check that data contents are preserved which were written with WRITE_ONCE_FLAG originally */ + status = SST_FUNCTION(s002_data[26].api, uid, 0, TEST_BUFF_SIZE, read_buff); + TEST_ASSERT_EQUAL(status, s002_data[26].status, TEST_CHECKPOINT_NUM(26)); + TEST_ASSERT_MEMCMP(write_buff, read_buff, TEST_BUFF_SIZE, TEST_CHECKPOINT_NUM(27)); + + /* Try to overwrite using set() with same UID as used before without WRITE_ONCE_FLAG */ + val->print(PRINT_TEST, "[Check 7] Try to change the WRITE_ONCE flag to None for UID %d\n", uid); + new_info.size = 0; + new_info.flags = 0; + status = SST_FUNCTION(s002_data[28].api, uid, (TEST_BUFF_SIZE - 1), write_buff_new, 0); + TEST_ASSERT_EQUAL(status, s002_data[28].status, TEST_CHECKPOINT_NUM(28)); + + /* Check that remove() still fails with PSA_SST_ERROR_WRITE_ONCE */ + val->print(PRINT_TEST, "[Check 8] Check UID removal still fails\n", 0); + status = SST_FUNCTION(s002_data[29].api, uid); + TEST_ASSERT_EQUAL(status, s002_data[29].status, TEST_CHECKPOINT_NUM(29)); + + /* Check that info is preserved */ + status = SST_FUNCTION(s002_data[30].api, uid, &new_info); + TEST_ASSERT_EQUAL(status, s002_data[30].status, TEST_CHECKPOINT_NUM(30)); + TEST_ASSERT_EQUAL(new_info.size, orig_info.size, TEST_CHECKPOINT_NUM(31)); + TEST_ASSERT_EQUAL(new_info.flags, orig_info.flags, TEST_CHECKPOINT_NUM(32)); + + return VAL_STATUS_SUCCESS; +} diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s002/test_s002.h b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s002/test_s002.h new file mode 100644 index 0000000..3a06eb9 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s002/test_s002.h @@ -0,0 +1,36 @@ +/** @file + * Copyright (c) 2019, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ +#ifndef _TEST_S002_CLIENT_TESTS_H_ +#define _TEST_S002_CLIENT_TESTS_H_ + +#ifdef ITS_TEST +#define VAL_STORAGE_BASE VAL_INTERNAL_TRUSTED_STORAGE_BASE +#define test_entry CONCAT(test_entry_, s002) +#elif PS_TEST +#define VAL_STORAGE_BASE VAL_PROTECTED_STORAGE_BASE +#define test_entry CONCAT(test_entry_, p002) +#endif +#define val CONCAT(val,test_entry) +#define psa CONCAT(psa,test_entry) + +extern val_api_t *val; +extern psa_api_t *psa; +extern client_test_t test_s002_sst_list[]; + +int32_t psa_sst_update_write_once_flag_after_create(caller_security_t caller); +int32_t psa_sst_create_with_write_once_flag(caller_security_t caller); +#endif /* _TEST_S002_CLIENT_TESTS_H_ */ diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s003/main.c b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s003/main.c new file mode 100644 index 0000000..fc7328c --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s003/main.c @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2020, Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "val_interfaces.h" +#include "pal_mbed_os_intf.h" +#include "lifecycle.h" + +#ifndef PS_ALLOW_ENTIRE_STORAGE_FILL +#error [NOT_SUPPORTED] Test is too long for CI, thus always fails on timeout. +#endif + +#ifdef ITS_TEST +void test_entry_s003(val_api_t *val_api, psa_api_t *psa_api); +#elif PS_TEST +void test_entry_p003(val_api_t *val_api, psa_api_t *psa_api); +#endif + +int main(void) +{ +#ifdef ITS_TEST + test_start(test_entry_s003, COMPLIANCE_TEST_STORAGE); +#elif PS_TEST + test_start(test_entry_p003, COMPLIANCE_TEST_STORAGE); +#endif + +} diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s003/test_entry.c b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s003/test_entry.c new file mode 100644 index 0000000..30dcbde --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s003/test_entry.c @@ -0,0 +1,53 @@ +/** @file + * Copyright (c) 2019, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ + +#include "val_interfaces.h" +#include "val_target.h" +#include "test_s003.h" + +#define TEST_NUM VAL_CREATE_TEST_ID(VAL_STORAGE_BASE, 3) +#define TEST_DESC "Insufficient space check\n" + +TEST_PUBLISH(TEST_NUM, test_entry); +val_api_t *val = NULL; +psa_api_t *psa = NULL; + +void test_entry(val_api_t *val_api, psa_api_t *psa_api) +{ + int32_t status = VAL_STATUS_SUCCESS; + + val = val_api; + psa = psa_api; + + /* test init */ + val->test_init(TEST_NUM, TEST_DESC, TEST_FIELD(TEST_ISOLATION_L1, WD_HIGH_TIMEOUT)); + if (!IS_TEST_START(val->get_status())) + { + goto test_exit; + } + + /* Execute list of tests available in test[num]_secure_storage_list from Non-secure side*/ + status = val->execute_non_secure_tests(TEST_NUM, test_s003_sst_list, FALSE); + + if (VAL_ERROR(status)) + { + goto test_exit; + } + +test_exit: + val->test_exit(); +} diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s003/test_its_data.h b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s003/test_its_data.h new file mode 100644 index 0000000..511e418 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s003/test_its_data.h @@ -0,0 +1,42 @@ +/** @file + * Copyright (c) 2019, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ +#ifndef _TEST_S003_ITS_DATA_TESTS_H_ +#define _TEST_S003_ITS_DATA_TESTS_H_ + +#include "val_internal_trusted_storage.h" + +#define SST_FUNCTION val->its_function +#define PSA_SST_SUCCESS PSA_ITS_SUCCESS +#define psa_sst_uid_t psa_its_uid_t + +typedef struct { + enum its_function_code api; + psa_its_status_t status; +} test_data; + +static const test_data s003_data[] = { +{ + 0, 0 /* This is dummy for index0 */ +}, +{ + VAL_ITS_SET, PSA_ITS_ERROR_INSUFFICIENT_SPACE /* Call set API till insufficent space */ +}, +{ + VAL_ITS_REMOVE, PSA_ITS_SUCCESS /* Remove the UID created */ +}, +}; +#endif /* _TEST_S003_ITS_DATA_TESTS_H_ */ diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s003/test_ps_data.h b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s003/test_ps_data.h new file mode 100644 index 0000000..db48c35 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s003/test_ps_data.h @@ -0,0 +1,42 @@ +/** @file + * Copyright (c) 2019, Arm Limited or ps affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ +#ifndef _TEST_S003_PS_DATA_TESTS_H_ +#define _TEST_S003_PS_DATA_TESTS_H_ + +#include "val_protected_storage.h" + +#define SST_FUNCTION val->ps_function +#define PSA_SST_SUCCESS PSA_PS_SUCCESS +#define psa_sst_uid_t psa_ps_uid_t + +typedef struct { + enum ps_function_code api; + psa_ps_status_t status; +} test_data; + +static const test_data s003_data[] = { +{ + 0, 0 /* This is dummy for index0 */ +}, +{ + VAL_PS_SET, PSA_PS_ERROR_INSUFFICIENT_SPACE /* Call set API till insufficent space */ +}, +{ + VAL_PS_REMOVE, PSA_PS_SUCCESS /* Remove the UID created */ +}, +}; +#endif /* _TEST_S003_PS_DATA_TESTS_H_ */ diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s003/test_s003.c b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s003/test_s003.c new file mode 100644 index 0000000..3475075 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s003/test_s003.c @@ -0,0 +1,96 @@ +/** @file + * Copyright (c) 2019, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ + +#include "val_interfaces.h" +#include "val_target.h" +#include "test_s003.h" +#if ITS_TEST +#include "test_its_data.h" +#elif PS_TEST +#include "test_ps_data.h" +#endif + +#define TEST_BUFF_SIZE 1024 +#define NUM_ITERATIONS 2 +#define TEST_BASE_UID_VALUE UID_BASE_VALUE + 5 + +client_test_t test_s003_sst_list[] = { + NULL, + psa_sst_insufficient_space, + NULL, +}; + +static uint8_t write_buff[TEST_BUFF_SIZE]; +static char test_desc[2][80] = { + "Overload storage space\n", + "Overload storage again to verify all previous UID removed\n"}; + +int32_t psa_sst_insufficient_space(caller_security_t caller) +{ + uint32_t status = PSA_SST_SUCCESS; + psa_sst_uid_t uid; + uint32_t count = 0, results[NUM_ITERATIONS] = {0}; + int i = 0; + + /* Saturate the storage for NUM_ITERATION times, and remove them after */ + for (i = 0 ; i < NUM_ITERATIONS; i++) + { + val->print(PRINT_TEST, "[Check %d] ", i + 1); + val->print(PRINT_TEST, &test_desc[i][0], 0); + for (uid = TEST_BASE_UID_VALUE; status == PSA_SST_SUCCESS; uid++) + { + val->print(PRINT_INFO, "Setting 0x%x bytes for ", TEST_BUFF_SIZE); + val->print(PRINT_INFO, "UID %d\n", uid); + status = SST_FUNCTION(s003_data[1].api, uid, TEST_BUFF_SIZE, write_buff, 0); + if (status != PSA_SST_SUCCESS) + { + val->print(PRINT_INFO, "UID %d set failed due to insufficient space\n", uid); + break; + } + } + TEST_ASSERT_EQUAL(status, s003_data[1].status, TEST_CHECKPOINT_NUM(1)); + + /* Store number of set()s it took to saturate the storage */ + count = uid - (TEST_BASE_UID_VALUE); + results[i] = uid - (TEST_BASE_UID_VALUE); + + if (count) + val->print(PRINT_TEST, "Remove all registered UIDs\n", 0); + for (uid = TEST_BASE_UID_VALUE; uid < (count + TEST_BASE_UID_VALUE); uid++) + { + val->print(PRINT_INFO, "Removing UID %d\n", uid); + status = SST_FUNCTION(s003_data[2].api, uid); + if (status != PSA_SST_SUCCESS) + break; + } + if (count) + TEST_ASSERT_EQUAL(status, s003_data[2].status, TEST_CHECKPOINT_NUM(2)); + } + + /* Check that it takes equal number of UIDs to fill up the storage each time */ + for (i = 0; i < (NUM_ITERATIONS -1); i++) + { + if (results[i] != results[i+1]) + { + val->print(PRINT_ERROR, "\tERROR : Mismatch between number of UIDs required to\n", 0); + val->print(PRINT_ERROR, "\t fill up the storage between iteration %d", i); + val->print(PRINT_ERROR, " and iteration %d\n", i+1); + return VAL_STATUS_ERROR; + } + } + return VAL_STATUS_SUCCESS; +} diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s003/test_s003.h b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s003/test_s003.h new file mode 100644 index 0000000..9fb4755 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s003/test_s003.h @@ -0,0 +1,35 @@ +/** @file + * Copyright (c) 2019, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ +#ifndef _TEST_S003_CLIENT_TESTS_H_ +#define _TEST_S003_CLIENT_TESTS_H_ + +#ifdef ITS_TEST +#define VAL_STORAGE_BASE VAL_INTERNAL_TRUSTED_STORAGE_BASE +#define test_entry CONCAT(test_entry_, s003) +#elif PS_TEST +#define VAL_STORAGE_BASE VAL_PROTECTED_STORAGE_BASE +#define test_entry CONCAT(test_entry_, p003) +#endif +#define val CONCAT(val,test_entry) +#define psa CONCAT(psa,test_entry) + +extern val_api_t *val; +extern psa_api_t *psa; +extern client_test_t test_s003_sst_list[]; + +int32_t psa_sst_insufficient_space(caller_security_t caller); +#endif /* _TEST_S003_CLIENT_TESTS_H_ */ diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s004/main.c b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s004/main.c new file mode 100644 index 0000000..20a623e --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s004/main.c @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020, Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "val_interfaces.h" +#include "pal_mbed_os_intf.h" +#if !defined(MBED_CONF_RTOS_PRESENT) +#error [NOT_SUPPORTED] PSA compliance its test cases require RTOS to run +#else + +#ifdef ITS_TEST +void test_entry_s004(val_api_t *val_api, psa_api_t *psa_api); +#elif PS_TEST +void test_entry_p004(val_api_t *val_api, psa_api_t *psa_api); +#endif + +int main(void) +{ +#ifdef ITS_TEST + test_start(test_entry_s004, COMPLIANCE_TEST_STORAGE); +#elif PS_TEST + test_start(test_entry_p004, COMPLIANCE_TEST_STORAGE); +#endif +} +#endif // !defined(MBED_CONF_RTOS_PRESENT) diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s004/test_entry.c b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s004/test_entry.c new file mode 100644 index 0000000..a6afc24 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s004/test_entry.c @@ -0,0 +1,53 @@ +/** @file + * Copyright (c) 2019, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ + +#include "val_interfaces.h" +#include "val_target.h" +#include "test_s004.h" + +#define TEST_NUM VAL_CREATE_TEST_ID(VAL_STORAGE_BASE, 4) +#define TEST_DESC "Data Consistency check\n" + +TEST_PUBLISH(TEST_NUM, test_entry); +val_api_t *val = NULL; +psa_api_t *psa = NULL; + +void test_entry(val_api_t *val_api, psa_api_t *psa_api) +{ + int32_t status = VAL_STATUS_SUCCESS; + + val = val_api; + psa = psa_api; + + /* test init */ + val->test_init(TEST_NUM, TEST_DESC, TEST_FIELD(TEST_ISOLATION_L1, WD_HIGH_TIMEOUT)); + if (!IS_TEST_START(val->get_status())) + { + goto test_exit; + } + + /* Execute list of tests available in test[num]_secure_storage_list from Non-secure side*/ + status = val->execute_non_secure_tests(TEST_NUM, test_s004_sst_list, FALSE); + + if (VAL_ERROR(status)) + { + goto test_exit; + } + +test_exit: + val->test_exit(); +} diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s004/test_its_data.h b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s004/test_its_data.h new file mode 100644 index 0000000..b41dc1b --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s004/test_its_data.h @@ -0,0 +1,65 @@ +/** @file + * Copyright (c) 2019, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ +#ifndef _TEST_S004_ITS_DATA_TESTS_H_ +#define _TEST_S004_ITS_DATA_TESTS_H_ + +#include "val_internal_trusted_storage.h" + +#define SST_FUNCTION val->its_function +#define psa_sst_uid_t psa_its_uid_t + +typedef struct { + enum its_function_code api; + psa_its_status_t status; +} test_data; + +static const test_data s004_data[] = { +{ + 0, 0 /* This is dummy for index0 */ +}, +{ + VAL_ITS_SET, PSA_ITS_SUCCESS /* Create a valid storage entity */ +}, +{ + VAL_ITS_GET, PSA_ITS_SUCCESS /* Validate the data using get API after set API failure */ +}, +{ + 0, 0 /* Index not used */ +}, +{ + VAL_ITS_SET, PSA_ITS_SUCCESS /* For same UID set the length as half of previous */ +}, +{ + VAL_ITS_GET, PSA_ITS_ERROR_INCORRECT_SIZE /* Call get with incorrect length */ +}, +{ + 0, 0 /* No data should be returned */ +}, +{ + VAL_ITS_GET, PSA_ITS_SUCCESS /* Call get API with correct length */ +}, +{ + 0, 0 /* No data should be returned */ +}, +{ + 0, 0 /* Check that we should not be able to access the old data */ +}, +{ + VAL_ITS_REMOVE, PSA_ITS_SUCCESS /* Remove the valid storage entity */ +}, +}; +#endif /* _TEST_S004_ITS_DATA_TESTS_H_ */ diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s004/test_ps_data.h b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s004/test_ps_data.h new file mode 100644 index 0000000..baaf194 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s004/test_ps_data.h @@ -0,0 +1,65 @@ +/** @file + * Copyright (c) 2019, Arm Limited or ps affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ +#ifndef _TEST_S004_PS_DATA_TESTS_H_ +#define _TEST_S004_PS_DATA_TESTS_H_ + +#include "val_protected_storage.h" + +#define SST_FUNCTION val->ps_function +#define psa_sst_uid_t psa_ps_uid_t + +typedef struct { + enum ps_function_code api; + psa_ps_status_t status; +} test_data; + +static const test_data s004_data[] = { +{ + 0, 0 /* This is dummy for index0 */ +}, +{ + VAL_PS_SET, PSA_PS_SUCCESS /* Create a valid storage entity */ +}, +{ + VAL_PS_GET, PSA_PS_SUCCESS /* Validate the data using get API after set API failure */ +}, +{ + 0, 0 /* Index not used */ +}, +{ + VAL_PS_SET, PSA_PS_SUCCESS /* For same UID set the length as half of previous */ +}, +{ + VAL_PS_GET, PSA_PS_ERROR_INCORRECT_SIZE /* Call get with incorrect length */ +}, +{ + 0, 0 /* No data should be returned */ +}, +{ + VAL_PS_GET, PSA_PS_SUCCESS /* Call get API with correct length */ +}, +{ + 0, 0 /* No data should be returned */ +}, +{ + 0, 0 /* Check that we should not be able to access the old data */ +}, +{ + VAL_PS_REMOVE, PSA_PS_SUCCESS /* Remove the valid storage entity */ +}, +}; +#endif /* _TEST_S004_PS_DATA_TESTS_H_ */ diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s004/test_s004.c b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s004/test_s004.c new file mode 100644 index 0000000..004ee2f --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s004/test_s004.c @@ -0,0 +1,84 @@ +/** @file + * Copyright (c) 2019, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ + +#include "val_interfaces.h" +#include "val_target.h" +#include "test_s004.h" +#ifdef ITS_TEST +#include "test_its_data.h" +#elif PS_TEST +#include "test_ps_data.h" +#endif + +#define TEST_BUFF_SIZE 20 + +client_test_t test_s004_sst_list[] = { + NULL, + psa_sst_get_data_check, + NULL, +}; + +static psa_sst_uid_t uid = UID_BASE_VALUE + 5; +static uint8_t read_buff[TEST_BUFF_SIZE] = {0}; +static uint8_t write_buff[TEST_BUFF_SIZE] = {0x99, 0x01, 0x30, 0x50, 0x04, 0x23, 0xF6, 0x07, 0x08, \ + 0x0D, 0x70, 0xA1, 0xFF, 0xFF, 0x14, 0x73, 0x46, 0x97, 0xE8, 0xDD}; + +int32_t psa_sst_get_data_check(caller_security_t caller) +{ + uint32_t status,j; + + /* Set data for UID */ + status = SST_FUNCTION(s004_data[1].api, uid, TEST_BUFF_SIZE, write_buff,0); + TEST_ASSERT_EQUAL(status, s004_data[1].status, TEST_CHECKPOINT_NUM(1)); + + /* Call get function and check the data consistency */ + status = SST_FUNCTION(s004_data[2].api, uid, 0, TEST_BUFF_SIZE, read_buff); + TEST_ASSERT_EQUAL(status, s004_data[2].status, TEST_CHECKPOINT_NUM(2)); + TEST_ASSERT_MEMCMP(read_buff, write_buff, TEST_BUFF_SIZE, TEST_CHECKPOINT_NUM(3)); + + /* Call the set again for same uid and set the length as half */ + status = SST_FUNCTION(s004_data[4].api, uid, TEST_BUFF_SIZE/2, write_buff, 0); + TEST_ASSERT_EQUAL(status, s004_data[4].status, TEST_CHECKPOINT_NUM(4)); + + /* Call get function with incorrect buffer length */ + val->print(PRINT_TEST, "[Check 1] Call get API with incorrect length\n", 0); + memset(read_buff, 0, TEST_BUFF_SIZE); + status = SST_FUNCTION(s004_data[5].api, uid, 0, TEST_BUFF_SIZE, read_buff); + TEST_ASSERT_EQUAL(status, s004_data[5].status, TEST_CHECKPOINT_NUM(5)); + for (j = 0; j < TEST_BUFF_SIZE; j++) + { + TEST_ASSERT_EQUAL(read_buff[j], 0, TEST_CHECKPOINT_NUM(6)); + } + + /* Call get function with CORRECT buffer length */ + status = SST_FUNCTION(s004_data[7].api, uid, 0, TEST_BUFF_SIZE/2, read_buff); + TEST_ASSERT_EQUAL(status, s004_data[7].status, TEST_CHECKPOINT_NUM(7)); + TEST_ASSERT_MEMCMP(read_buff, write_buff, TEST_BUFF_SIZE/2, TEST_CHECKPOINT_NUM(8)); + + /* Check we should not be able to access old set data */ + val->print(PRINT_TEST, "[Check 2] Old buffer invalid after length change\n", 0); + for (j = TEST_BUFF_SIZE/2; j < TEST_BUFF_SIZE; j++) + { + TEST_ASSERT_EQUAL(read_buff[j], 0, TEST_CHECKPOINT_NUM(9)); + } + + /* Remove the UID */ + status = SST_FUNCTION(s004_data[10].api, uid); + TEST_ASSERT_EQUAL(status, s004_data[10].status, TEST_CHECKPOINT_NUM(10)); + + return VAL_STATUS_SUCCESS; +} diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s004/test_s004.h b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s004/test_s004.h new file mode 100644 index 0000000..03c6ad1 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s004/test_s004.h @@ -0,0 +1,35 @@ +/** @file + * Copyright (c) 2019, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ +#ifndef _TEST_S004_CLIENT_TESTS_H_ +#define _TEST_S004_CLIENT_TESTS_H_ + +#ifdef ITS_TEST +#define VAL_STORAGE_BASE VAL_INTERNAL_TRUSTED_STORAGE_BASE +#define test_entry CONCAT(test_entry_, s004) +#elif PS_TEST +#define VAL_STORAGE_BASE VAL_PROTECTED_STORAGE_BASE +#define test_entry CONCAT(test_entry_, p004) +#endif +#define val CONCAT(val,test_entry) +#define psa CONCAT(psa,test_entry) + +extern val_api_t *val; +extern psa_api_t *psa; +extern client_test_t test_s004_sst_list[]; + +int32_t psa_sst_get_data_check(caller_security_t caller); +#endif /* _TEST_S004_CLIENT_TESTS_H_ */ diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s005/main.c b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s005/main.c new file mode 100644 index 0000000..b15f531 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s005/main.c @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2020, Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "val_interfaces.h" +#include "pal_mbed_os_intf.h" + +#if !defined(MBED_CONF_RTOS_PRESENT) +#error [NOT_SUPPORTED] PSA compliance its test cases require RTOS to run +#else + +#ifdef ITS_TEST +void test_entry_s005(val_api_t *val_api, psa_api_t *psa_api); +#elif PS_TEST +void test_entry_p005(val_api_t *val_api, psa_api_t *psa_api); +#endif + +int main(void) +{ +#ifdef ITS_TEST + test_start(test_entry_s005, COMPLIANCE_TEST_STORAGE); +#elif PS_TEST + test_start(test_entry_p005, COMPLIANCE_TEST_STORAGE); +#endif +} +#endif // !defined(MBED_CONF_RTOS_PRESENT) diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s005/test_entry.c b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s005/test_entry.c new file mode 100644 index 0000000..36dcbaa --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s005/test_entry.c @@ -0,0 +1,52 @@ +/** @file + * Copyright (c) 2019, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ + +#include "val_interfaces.h" +#include "val_target.h" +#include "test_s005.h" + +#define TEST_NUM VAL_CREATE_TEST_ID(VAL_STORAGE_BASE, 5) +#define TEST_DESC "Success scenarios check\n" + +TEST_PUBLISH(TEST_NUM, test_entry); +val_api_t *val = NULL; +psa_api_t *psa = NULL; + +void test_entry(val_api_t *val_api, psa_api_t *psa_api) +{ + int32_t status = VAL_STATUS_SUCCESS; + + val = val_api; + psa = psa_api; + + /* test init */ + val->test_init(TEST_NUM, TEST_DESC, TEST_FIELD(TEST_ISOLATION_L1, WD_HIGH_TIMEOUT)); + if (!IS_TEST_START(val->get_status())) + { + goto test_exit; + } + + /* Execute list of tests available in test[num]_secure_storage_list from Non-secure side*/ + status = val->execute_non_secure_tests(TEST_NUM, test_s005_sst_list, FALSE); + if (VAL_ERROR(status)) + { + goto test_exit; + } + +test_exit: + val->test_exit(); +} diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s005/test_its_data.h b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s005/test_its_data.h new file mode 100644 index 0000000..653f7cc --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s005/test_its_data.h @@ -0,0 +1,58 @@ +/** @file + * Copyright (c) 2019, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ +#ifndef _TEST_S005_ITS_DATA_TESTS_H_ +#define _TEST_S005_ITS_DATA_TESTS_H_ + +#include "val_internal_trusted_storage.h" + +#define SST_FUNCTION val->its_function +#define psa_sst_uid_t psa_its_uid_t +#define psa_sst_create_flags_t psa_its_create_flags_t + +typedef struct { + enum its_function_code api; + psa_its_status_t status; +} test_data; + +static struct psa_its_info_t info; +static const test_data s005_data[] = { +{ + 0, 0 /* This is dummy for index0 */ +}, +{ + VAL_ITS_SET, PSA_ITS_SUCCESS /* Create a valid storage entity */ +}, +{ + VAL_ITS_GET, PSA_ITS_SUCCESS /* Validate the data using get API */ +}, +{ + 0, 0 /* Index not used */ +}, +{ + VAL_ITS_GET_INFO, PSA_ITS_SUCCESS /* Validate the data attributes get_info API */ +}, +{ + 0, 0 /* Index not used */ +}, +{ + 0, 0 /* Index not used */ +}, +{ + VAL_ITS_REMOVE, PSA_ITS_SUCCESS /* Remove the valid storage entity */ +}, +}; +#endif /* _TEST_S005_ITS_DATA_TESTS_H_ */ diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s005/test_ps_data.h b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s005/test_ps_data.h new file mode 100644 index 0000000..a961269 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s005/test_ps_data.h @@ -0,0 +1,58 @@ +/** @file + * Copyright (c) 2019, Arm Limited or ps affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ +#ifndef _TEST_S005_PS_DATA_TESTS_H_ +#define _TEST_S005_PS_DATA_TESTS_H_ + +#include "val_protected_storage.h" + +#define SST_FUNCTION val->ps_function +#define psa_sst_uid_t psa_ps_uid_t +#define psa_sst_create_flags_t psa_ps_create_flags_t + +typedef struct { + enum ps_function_code api; + psa_ps_status_t status; +} test_data; + +static struct psa_ps_info_t info; +static const test_data s005_data[] = { +{ + 0, 0 /* This is dummy for index0 */ +}, +{ + VAL_PS_SET, PSA_PS_SUCCESS /* Create a valid storage entity */ +}, +{ + VAL_PS_GET, PSA_PS_SUCCESS /* Validate the data using get API */ +}, +{ + 0, 0 /* Index not used */ +}, +{ + VAL_PS_GET_INFO, PSA_PS_SUCCESS /* Validate the data attributes get_info API */ +}, +{ + 0, 0 /* Index not used */ +}, +{ + 0, 0 /* Index not used */ +}, +{ + VAL_PS_REMOVE, PSA_PS_SUCCESS /* Remove the valid storage entity */ +}, +}; +#endif /* _TEST_S005_PS_DATA_TESTS_H_ */ diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s005/test_s005.c b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s005/test_s005.c new file mode 100644 index 0000000..c974d04 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s005/test_s005.c @@ -0,0 +1,89 @@ +/** @file + * Copyright (c) 2019, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ + +#include "val_interfaces.h" +#include "val_target.h" +#include "test_s005.h" +#ifdef ITS_TEST +#include "test_its_data.h" +#elif PS_TEST +#include "test_ps_data.h" +#endif + +#define TEST_BUFF_SIZE 30 + +client_test_t test_s005_sst_list[] = { + NULL, + psa_sst_apis_check_success_case, + NULL, +}; + +static uint8_t read_buff[TEST_BUFF_SIZE]; +static uint8_t write_buff[TEST_BUFF_SIZE] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x23, 0xF6, 0x07, 0x08, 0x0D, 0x0A, 0x1B, 0x0C, 0x5D, 0x0E,\ + 0x70, 0xA1, 0xFF, 0xFF, 0x14, 0x73, 0x46, 0x97, 0xE8, 0xDD, 0xCA, 0x0B, 0x3C, 0x0D, 0x2E}; + +static int32_t psa_sst_apis_check(psa_sst_uid_t uid, uint32_t data_len, + uint8_t *data_buff, psa_sst_create_flags_t create_flag) +{ + uint32_t status; + + /* Set the UID with the data_len and data_buff */ + status = SST_FUNCTION(s005_data[1].api, uid, data_len, data_buff, create_flag); + TEST_ASSERT_EQUAL(status, s005_data[1].status, TEST_CHECKPOINT_NUM(1)); + + /* Call the get function to get the data buffer and match the buffer */ + status = SST_FUNCTION(s005_data[2].api, uid, 0, data_len, read_buff); + TEST_ASSERT_EQUAL(status, s005_data[2].status, TEST_CHECKPOINT_NUM(2)); + TEST_ASSERT_MEMCMP(read_buff, data_buff, data_len, TEST_CHECKPOINT_NUM(3)); + + /* Call the get_info function and match the attributes */ + status = SST_FUNCTION(s005_data[4].api, uid, &info); + TEST_ASSERT_EQUAL(status, s005_data[4].status, TEST_CHECKPOINT_NUM(4)); + TEST_ASSERT_EQUAL(info.size, data_len, TEST_CHECKPOINT_NUM(5)); + TEST_ASSERT_EQUAL(info.flags, create_flag, TEST_CHECKPOINT_NUM(6)); + + /* Remove the UID */ + status = SST_FUNCTION(s005_data[7].api, uid); + TEST_ASSERT_EQUAL(status, s005_data[7].status, TEST_CHECKPOINT_NUM(7)); + + return VAL_STATUS_SUCCESS; +} + +int32_t psa_sst_apis_check_success_case(caller_security_t caller) +{ + psa_sst_uid_t uid = UID_BASE_VALUE + 4; + uint32_t data_len = 0, status = VAL_STATUS_SUCCESS; + + /* Calling set function with data_len 1 and valid data pointer */ + val->print(PRINT_TEST, "[Check 1] Set UID with data length zero and call storage APIs\n", 0); + if (psa_sst_apis_check(uid, data_len, write_buff, 0)) + { + val->print(PRINT_ERROR, "Data Len = %d\n", data_len); + return VAL_STATUS_ERROR; + } + + data_len = TEST_BUFF_SIZE/2; + val->print(PRINT_TEST, "[Check 2] Resetting the length check\n", 0); + if (psa_sst_apis_check(uid, data_len, write_buff, 0)) + { + val->print(PRINT_ERROR, "Data Len = %d\n", data_len); + return VAL_STATUS_ERROR; + } + + return status; +} diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s005/test_s005.h b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s005/test_s005.h new file mode 100644 index 0000000..9451737 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s005/test_s005.h @@ -0,0 +1,36 @@ +/** @file + * Copyright (c) 2019, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ +#ifndef _TEST_S005_CLIENT_TESTS_H_ +#define _TEST_S005_CLIENT_TESTS_H_ + +#ifdef ITS_TEST +#define VAL_STORAGE_BASE VAL_INTERNAL_TRUSTED_STORAGE_BASE +#define test_entry CONCAT(test_entry_, s005) +#elif PS_TEST +#define VAL_STORAGE_BASE VAL_PROTECTED_STORAGE_BASE +#define test_entry CONCAT(test_entry_, p005) +#endif +#define val CONCAT(val,test_entry) +#define psa CONCAT(psa,test_entry) + +extern val_api_t *val; +extern psa_api_t *psa; +extern client_test_t test_s005_sst_list[]; + +int32_t psa_sst_apis_check_success_case(caller_security_t caller); + +#endif /* _TEST_S005_CLIENT_TESTS_H_ */ diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s006/main.c b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s006/main.c new file mode 100644 index 0000000..1a24de7 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s006/main.c @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2020, Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "val_interfaces.h" +#include "pal_mbed_os_intf.h" + +#if !defined(MBED_CONF_RTOS_PRESENT) +#error [NOT_SUPPORTED] PSA compliance its test cases require RTOS to run +#else + +#ifdef ITS_TEST +void test_entry_s006(val_api_t *val_api, psa_api_t *psa_api); +#elif PS_TEST +void test_entry_p006(val_api_t *val_api, psa_api_t *psa_api); +#endif + +int main(void) +{ +#ifdef ITS_TEST + test_start(test_entry_s006, COMPLIANCE_TEST_STORAGE); +#elif PS_TEST + test_start(test_entry_p006, COMPLIANCE_TEST_STORAGE); +#endif +} +#endif // !defined(MBED_CONF_RTOS_PRESENT) diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s006/test_entry.c b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s006/test_entry.c new file mode 100644 index 0000000..dda491b --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s006/test_entry.c @@ -0,0 +1,52 @@ +/** @file + * Copyright (c) 2019, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ + +#include "val_interfaces.h" +#include "val_target.h" +#include "test_s006.h" + +#define TEST_NUM VAL_CREATE_TEST_ID(VAL_STORAGE_BASE, 6) +#define TEST_DESC "Flags not supported check\n" + +TEST_PUBLISH(TEST_NUM, test_entry); +val_api_t *val = NULL; +psa_api_t *psa = NULL; + +void test_entry(val_api_t *val_api, psa_api_t *psa_api) +{ + int32_t status = VAL_STATUS_SUCCESS; + + val = val_api; + psa = psa_api; + + /* test init */ + val->test_init(TEST_NUM, TEST_DESC, TEST_FIELD(TEST_ISOLATION_L1, WD_HIGH_TIMEOUT)); + if (!IS_TEST_START(val->get_status())) + { + goto test_exit; + } + + /* Execute list of tests available in test[num]_secure_storage_list from Non-secure side*/ + status = val->execute_non_secure_tests(TEST_NUM, test_s006_sst_list, FALSE); + if (VAL_ERROR(status)) + { + goto test_exit; + } + +test_exit: + val->test_exit(); +} diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s006/test_its_data.h b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s006/test_its_data.h new file mode 100644 index 0000000..4426f2c --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s006/test_its_data.h @@ -0,0 +1,53 @@ +/** @file + * Copyright (c) 2019, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ +#ifndef _TEST_S006_ITS_DATA_TESTS_H_ +#define _TEST_S006_ITS_DATA_TESTS_H_ + +#include "val_internal_trusted_storage.h" + +#define SST_FUNCTION val->its_function +#define PSA_SST_FLAG_WRITE_ONCE PSA_ITS_FLAG_WRITE_ONCE +#define psa_sst_uid_t psa_its_uid_t +#define psa_sst_create_flags_t psa_its_create_flags_t + +typedef struct { + enum its_function_code api; + psa_its_status_t status; +} test_data; + +static struct psa_its_info_t info; +static const test_data s006_data[] = { +{ + 0, PSA_ITS_ERROR_FLAGS_NOT_SUPPORTED /* This is dummy for index0 */ +}, +{ + VAL_ITS_SET, PSA_ITS_SUCCESS /* Create a valid storage entity with different flag values */ +}, +{ + VAL_ITS_GET_INFO, PSA_ITS_SUCCESS /* Validate the flag value get_info API */ +}, +{ + 0, 0 /* Index not used */ +}, +{ + VAL_ITS_REMOVE, PSA_ITS_SUCCESS /* Remove the storage entity */ +}, +{ + VAL_ITS_REMOVE, PSA_ITS_ERROR_UID_NOT_FOUND /* Storage entity remove fails */ +}, +}; +#endif /* _TEST_S006_ITS_DATA_TESTS_H_ */ diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s006/test_ps_data.h b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s006/test_ps_data.h new file mode 100644 index 0000000..86e1e30 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s006/test_ps_data.h @@ -0,0 +1,53 @@ +/** @file + * Copyright (c) 2019, Arm Limited or ps affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ +#ifndef _TEST_S006_PS_DATA_TESTS_H_ +#define _TEST_S006_PS_DATA_TESTS_H_ + +#include "val_protected_storage.h" + +#define SST_FUNCTION val->ps_function +#define PSA_SST_FLAG_WRITE_ONCE PSA_PS_FLAG_WRITE_ONCE +#define psa_sst_uid_t psa_ps_uid_t +#define psa_sst_create_flags_t psa_ps_create_flags_t + +typedef struct { + enum ps_function_code api; + psa_ps_status_t status; +} test_data; + +static struct psa_ps_info_t info; +static const test_data s006_data[] = { +{ + 0, PSA_PS_ERROR_FLAGS_NOT_SUPPORTED /* This is dummy for index0 */ +}, +{ + VAL_PS_SET, PSA_PS_SUCCESS /* Create a valid storage entity with different flag values */ +}, +{ + VAL_PS_GET_INFO, PSA_PS_SUCCESS /* Validate the flag value get_info API */ +}, +{ + 0, 0 /* Index not used */ +}, +{ + VAL_PS_REMOVE, PSA_PS_SUCCESS /* Remove the storage entity */ +}, +{ + VAL_PS_REMOVE, PSA_PS_ERROR_UID_NOT_FOUND /* Remove the storage entity */ +} +}; +#endif /* _TEST_S006_PS_DATA_TESTS_H_ */ diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s006/test_s006.c b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s006/test_s006.c new file mode 100644 index 0000000..26b8984 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s006/test_s006.c @@ -0,0 +1,90 @@ +/** @file + * Copyright (c) 2019, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ + +#include "val_interfaces.h" +#include "val_target.h" +#include "test_s006.h" +#ifdef ITS_TEST +#include "test_its_data.h" +#elif PS_TEST +#include "test_ps_data.h" +#endif + +#define TEST_BUFF_SIZE 30 + +client_test_t test_s006_sst_list[] = { + NULL, + psa_sst_flags_not_supported, + NULL, +}; + +static uint8_t write_buff[TEST_BUFF_SIZE] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x23, 0xF6, 0x07, 0x08, 0x0D, 0x0A, 0x1B, 0x0C, 0x5D, 0x0E,\ + 0x70, 0xA1, 0xFF, 0xFF, 0x14, 0x73, 0x46, 0x97, 0xE8, 0xDD, 0xCA, 0x0B, 0x3C, 0x0D, 0x2E}; + +static int32_t psa_sst_remove_api(psa_sst_uid_t uid, uint32_t data_len, + uint8_t *data_buff, psa_sst_create_flags_t create_flag) +{ + uint32_t status; + + /* Call the get_info function and match the attributes */ + status = SST_FUNCTION(s006_data[2].api, uid, &info); + TEST_ASSERT_EQUAL(status, s006_data[2].status, TEST_CHECKPOINT_NUM(2)); + TEST_ASSERT_EQUAL(info.flags, create_flag, TEST_CHECKPOINT_NUM(3)); + + /* Remove the UID */ + status = SST_FUNCTION(s006_data[4].api, uid); + TEST_ASSERT_EQUAL(status, s006_data[4].status, TEST_CHECKPOINT_NUM(4)); + + return VAL_STATUS_SUCCESS; +} + +int32_t psa_sst_flags_not_supported(caller_security_t caller) +{ + psa_sst_create_flags_t flag = 0x80000000; + uint32_t status = VAL_STATUS_SUCCESS; + psa_sst_uid_t uid = UID_BASE_VALUE + 5; + int32_t test_status; + + /* Calling set function with different create flag value */ + + val->print(PRINT_TEST, "[Check 1] Call set API with valid flag values\n", 0); + while (flag) + { + /* Create storage with flag value */ + status = SST_FUNCTION(s006_data[1].api, uid, TEST_BUFF_SIZE, write_buff, + (flag & (~PSA_SST_FLAG_WRITE_ONCE))); + + if (status == s006_data[1].status) + { + test_status = psa_sst_remove_api(uid, TEST_BUFF_SIZE, write_buff, + (flag & (~PSA_SST_FLAG_WRITE_ONCE))); + if (test_status != VAL_STATUS_SUCCESS) + return test_status; + } + else if (status == s006_data[0].status) + { + /* Remove UID should fail */ + status = SST_FUNCTION(s006_data[5].api, uid); + TEST_ASSERT_EQUAL(status, s006_data[5].status, TEST_CHECKPOINT_NUM(5)); + } + + flag = flag >> 1; + }; + + return status; +} diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s006/test_s006.h b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s006/test_s006.h new file mode 100644 index 0000000..9e79324 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s006/test_s006.h @@ -0,0 +1,36 @@ +/** @file + * Copyright (c) 2019, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ +#ifndef _TEST_S006_CLIENT_TESTS_H_ +#define _TEST_S006_CLIENT_TESTS_H_ + +#ifdef ITS_TEST +#define VAL_STORAGE_BASE VAL_INTERNAL_TRUSTED_STORAGE_BASE +#define test_entry CONCAT(test_entry_, s006) +#elif PS_TEST +#define VAL_STORAGE_BASE VAL_PROTECTED_STORAGE_BASE +#define test_entry CONCAT(test_entry_, p006) +#endif +#define val CONCAT(val,test_entry) +#define psa CONCAT(psa,test_entry) + +extern val_api_t *val; +extern psa_api_t *psa; +extern client_test_t test_s006_sst_list[]; + +int32_t psa_sst_flags_not_supported(caller_security_t caller); + +#endif /* _TEST_S006_CLIENT_TESTS_H_ */ diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s007/main.c b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s007/main.c new file mode 100644 index 0000000..a63001e --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s007/main.c @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2020, Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "val_interfaces.h" +#include "pal_mbed_os_intf.h" + +#if !defined(MBED_CONF_RTOS_PRESENT) +#error [NOT_SUPPORTED] PSA compliance its test cases require RTOS to run +#else + +#ifdef ITS_TEST +void test_entry_s007(val_api_t *val_api, psa_api_t *psa_api); +#elif PS_TEST +void test_entry_p007(val_api_t *val_api, psa_api_t *psa_api); +#endif + +int main(void) +{ +#ifdef ITS_TEST + test_start(test_entry_s007, COMPLIANCE_TEST_STORAGE); +#elif PS_TEST + test_start(test_entry_p007, COMPLIANCE_TEST_STORAGE); +#endif +} +#endif // !defined(MBED_CONF_RTOS_PRESENT) diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s007/test_entry.c b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s007/test_entry.c new file mode 100644 index 0000000..f6005a1 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s007/test_entry.c @@ -0,0 +1,52 @@ +/** @file + * Copyright (c) 2019, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ + +#include "val_interfaces.h" +#include "val_target.h" +#include "test_s007.h" + +#define TEST_NUM VAL_CREATE_TEST_ID(VAL_STORAGE_BASE, 7) +#define TEST_DESC "Incorrect Size check\n" + +TEST_PUBLISH(TEST_NUM, test_entry); +val_api_t *val = NULL; +psa_api_t *psa = NULL; + +void test_entry(val_api_t *val_api, psa_api_t *psa_api) +{ + int32_t status = VAL_STATUS_SUCCESS; + + val = val_api; + psa = psa_api; + + /* test init */ + val->test_init(TEST_NUM, TEST_DESC, TEST_FIELD(TEST_ISOLATION_L1, WD_HIGH_TIMEOUT)); + if (!IS_TEST_START(val->get_status())) + { + goto test_exit; + } + + /* Execute list of tests available in test[num]_secure_storage_list from Non-secure side*/ + status = val->execute_non_secure_tests(TEST_NUM, test_s007_sst_list, FALSE); + if (VAL_ERROR(status)) + { + goto test_exit; + } + +test_exit: + val->test_exit(); +} diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s007/test_its_data.h b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s007/test_its_data.h new file mode 100644 index 0000000..550dffb --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s007/test_its_data.h @@ -0,0 +1,65 @@ +/** @file + * Copyright (c) 2019, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ +#ifndef _TEST_S007_ITS_DATA_TESTS_H_ +#define _TEST_S007_ITS_DATA_TESTS_H_ + +#include "val_internal_trusted_storage.h" + +#define SST_FUNCTION val->its_function +#define psa_sst_uid_t psa_its_uid_t + +typedef struct { + enum its_function_code api; + psa_its_status_t status; +} test_data; + +static const test_data s007_data[] = { +{ + 0, 0 /* This is dummy for index0 */ +}, +{ + VAL_ITS_SET, PSA_ITS_SUCCESS /* Create a valid storage entity */ +}, +{ + VAL_ITS_SET, PSA_ITS_SUCCESS /* Increase the length of storage */ +}, +{ + VAL_ITS_GET, PSA_ITS_SUCCESS /* Try to access old length */ +}, +{ + VAL_ITS_GET, PSA_ITS_SUCCESS /* Try to access valid length less than set length */ +}, +{ + 0, 0 /* This is dummy for index5 */ +}, +{ + VAL_ITS_SET, PSA_ITS_SUCCESS /* Decrease the length of storage */ +}, +{ + VAL_ITS_GET, PSA_ITS_ERROR_INCORRECT_SIZE /* Try to access old length */ +}, +{ + VAL_ITS_GET, PSA_ITS_ERROR_INCORRECT_SIZE /* Try to access old length */ +}, +{ + VAL_ITS_GET, PSA_ITS_SUCCESS /* Try to access data with correct length */ +}, +{ + VAL_ITS_REMOVE, PSA_ITS_SUCCESS /* Remove the storage entity */ +}, +}; +#endif /* _TEST_S007_ITS_DATA_TESTS_H_ */ diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s007/test_ps_data.h b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s007/test_ps_data.h new file mode 100644 index 0000000..fa032c1 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s007/test_ps_data.h @@ -0,0 +1,65 @@ +/** @file + * Copyright (c) 2019, Arm Limited or ps affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ +#ifndef _TEST_S007_PS_DATA_TESTS_H_ +#define _TEST_S007_PS_DATA_TESTS_H_ + +#include "val_protected_storage.h" + +#define SST_FUNCTION val->ps_function +#define psa_sst_uid_t psa_ps_uid_t + +typedef struct { + enum ps_function_code api; + psa_ps_status_t status; +} test_data; + +static const test_data s007_data[] = { +{ + 0, 0 /* This is dummy for index0 */ +}, +{ + VAL_PS_SET, PSA_PS_SUCCESS /* Create a valid storage entity */ +}, +{ + VAL_PS_SET, PSA_PS_SUCCESS /* Increase the length of storage */ +}, +{ + VAL_PS_GET, PSA_PS_SUCCESS /* Try to access old length */ +}, +{ + VAL_PS_GET, PSA_PS_SUCCESS /* Try to access valid length less than set length */ +}, +{ + 0, 0 /* This is dummy for index5 */ +}, +{ + VAL_PS_SET, PSA_PS_SUCCESS /* Decrease the length of storage */ +}, +{ + VAL_PS_GET, PSA_PS_ERROR_INCORRECT_SIZE /* Try to access old length */ +}, +{ + VAL_PS_GET, PSA_PS_ERROR_INCORRECT_SIZE /* Try to access old length */ +}, +{ + VAL_PS_GET, PSA_PS_SUCCESS /* Try to access data with correct length */ +}, +{ + VAL_PS_REMOVE, PSA_PS_SUCCESS /* Remove the storage entity */ +}, +}; +#endif /* _TEST_S007_PS_DATA_TESTS_H_ */ diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s007/test_s007.c b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s007/test_s007.c new file mode 100644 index 0000000..b17143c --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s007/test_s007.c @@ -0,0 +1,89 @@ +/** @file + * Copyright (c) 2019, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ + +#include "val_interfaces.h" +#include "val_target.h" +#include "test_s007.h" +#ifdef ITS_TEST +#include "test_its_data.h" +#elif PS_TEST +#include "test_ps_data.h" +#endif + +#define TEST_BUFF_SIZE 30 + +client_test_t test_s007_sst_list[] = { + NULL, + psa_sst_get_incorrect_size, + NULL, +}; + +static uint8_t write_buff[TEST_BUFF_SIZE] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x23, 0xF6, 0x07, 0x08, 0x0D, 0x0A, 0x1B, 0x0C, 0x5D, 0x0E,\ + 0x70, 0xA1, 0xFF, 0xFF, 0x14, 0x73, 0x46, 0x97, 0xE8, 0xDD, 0xCA, 0x0B, 0x3C, 0x0D, 0x2E}; +static uint8_t read_buff[TEST_BUFF_SIZE]; + +int32_t psa_sst_get_incorrect_size(caller_security_t caller) +{ + psa_sst_uid_t uid = UID_BASE_VALUE + 5; + uint32_t status = VAL_STATUS_SUCCESS; + + /* Set the UID with the data_len and data_buff */ + val->print(PRINT_TEST, "Create a valid Storage\n", 0); + status = SST_FUNCTION(s007_data[1].api, uid, TEST_BUFF_SIZE/2, write_buff, 0); + TEST_ASSERT_EQUAL(status, s007_data[1].status, TEST_CHECKPOINT_NUM(1)); + + /* Call set for same UID and increase the length */ + val->print(PRINT_TEST, "Increase the length of storage\n", 0); + status = SST_FUNCTION(s007_data[2].api, uid, TEST_BUFF_SIZE, write_buff, 0); + TEST_ASSERT_EQUAL(status, s007_data[2].status, TEST_CHECKPOINT_NUM(2)); + + /* Access data using get API and old length */ + val->print(PRINT_TEST, "[Check 1] Call get API with old length\n", 0); + status = SST_FUNCTION(s007_data[3].api, uid, 0, TEST_BUFF_SIZE/2, read_buff); + TEST_ASSERT_EQUAL(status, s007_data[3].status, TEST_CHECKPOINT_NUM(3)); + + /* Access data using get API and valid length */ + status = SST_FUNCTION(s007_data[4].api, uid, 0, TEST_BUFF_SIZE/4, read_buff); + TEST_ASSERT_EQUAL(status, s007_data[4].status, TEST_CHECKPOINT_NUM(4)); + TEST_ASSERT_MEMCMP(read_buff, write_buff, TEST_BUFF_SIZE/4, TEST_CHECKPOINT_NUM(5)); + + /* Decrease the length again */ + val->print(PRINT_TEST, "Decrease the length of storage\n", 0); + status = SST_FUNCTION(s007_data[6].api, uid, TEST_BUFF_SIZE/4, write_buff, 0); + TEST_ASSERT_EQUAL(status, s007_data[6].status, TEST_CHECKPOINT_NUM(6)); + + /* Access data using get API and old length */ + status = SST_FUNCTION(s007_data[7].api, uid, 0, TEST_BUFF_SIZE/2, read_buff); + TEST_ASSERT_EQUAL(status, s007_data[7].status, TEST_CHECKPOINT_NUM(7)); + + /* Access data using get API and old length */ + val->print(PRINT_TEST, "[Check 2] Call get API with old length\n", 0); + status = SST_FUNCTION(s007_data[8].api, uid, 0, TEST_BUFF_SIZE, read_buff); + TEST_ASSERT_EQUAL(status, s007_data[8].status, TEST_CHECKPOINT_NUM(8)); + + /* Access data using correct length */ + val->print(PRINT_TEST, "[Check 3] Call get API with valid length\n", 0); + status = SST_FUNCTION(s007_data[9].api, uid, 0, TEST_BUFF_SIZE/4, read_buff); + TEST_ASSERT_EQUAL(status, s007_data[9].status, TEST_CHECKPOINT_NUM(9)); + + /* Remove the UID */ + status = SST_FUNCTION(s007_data[10].api, uid); + TEST_ASSERT_EQUAL(status, s007_data[10].status, TEST_CHECKPOINT_NUM(10)); + + return status; +} diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s007/test_s007.h b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s007/test_s007.h new file mode 100644 index 0000000..b663980 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s007/test_s007.h @@ -0,0 +1,36 @@ +/** @file + * Copyright (c) 2019, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ +#ifndef _TEST_S007_CLIENT_TESTS_H_ +#define _TEST_S007_CLIENT_TESTS_H_ + +#ifdef ITS_TEST +#define VAL_STORAGE_BASE VAL_INTERNAL_TRUSTED_STORAGE_BASE +#define test_entry CONCAT(test_entry_, s007) +#elif PS_TEST +#define VAL_STORAGE_BASE VAL_PROTECTED_STORAGE_BASE +#define test_entry CONCAT(test_entry_, p007) +#endif +#define val CONCAT(val,test_entry) +#define psa CONCAT(psa,test_entry) + +extern val_api_t *val; +extern psa_api_t *psa; +extern client_test_t test_s007_sst_list[]; + +int32_t psa_sst_get_incorrect_size(caller_security_t caller); + +#endif /* _TEST_S007_CLIENT_TESTS_H_ */ diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s008/main.c b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s008/main.c new file mode 100644 index 0000000..b17f6cf --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s008/main.c @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2020, Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "val_interfaces.h" +#include "pal_mbed_os_intf.h" + +#if !defined(MBED_CONF_RTOS_PRESENT) +#error [NOT_SUPPORTED] PSA compliance its test cases require RTOS to run +#else + +#ifdef ITS_TEST +void test_entry_s008(val_api_t *val_api, psa_api_t *psa_api); +#elif PS_TEST +void test_entry_p008(val_api_t *val_api, psa_api_t *psa_api); +#endif + +int main(void) +{ +#ifdef ITS_TEST + test_start(test_entry_s008, COMPLIANCE_TEST_STORAGE); +#elif PS_TEST + test_start(test_entry_p008, COMPLIANCE_TEST_STORAGE); +#endif +} +#endif // !defined(MBED_CONF_RTOS_PRESENT) diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s008/test_entry.c b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s008/test_entry.c new file mode 100644 index 0000000..f531881 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s008/test_entry.c @@ -0,0 +1,53 @@ +/** @file + * Copyright (c) 2019, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ + +#include "val_interfaces.h" +#include "val_target.h" +#include "test_s008.h" + +#define TEST_NUM VAL_CREATE_TEST_ID(VAL_STORAGE_BASE, 8) +#define TEST_DESC "Invalid offset check\n" + +TEST_PUBLISH(TEST_NUM, test_entry); +val_api_t *val = NULL; +psa_api_t *psa = NULL; + +void test_entry(val_api_t *val_api, psa_api_t *psa_api) +{ + int32_t status = VAL_STATUS_SUCCESS; + + val = val_api; + psa = psa_api; + + /* test init */ + val->test_init(TEST_NUM, TEST_DESC, TEST_FIELD(TEST_ISOLATION_L1, WD_HIGH_TIMEOUT)); + if (!IS_TEST_START(val->get_status())) + { + goto test_exit; + } + + /* Execute list of tests available in test[num]_secure_storage_list from Non-secure side*/ + status = val->execute_non_secure_tests(TEST_NUM, test_s008_sst_list, FALSE); + + if (VAL_ERROR(status)) + { + goto test_exit; + } + +test_exit: + val->test_exit(); +} diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s008/test_its_data.h b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s008/test_its_data.h new file mode 100644 index 0000000..89093d4 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s008/test_its_data.h @@ -0,0 +1,74 @@ +/** @file + * Copyright (c) 2019, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ +#ifndef _TEST_S008_ITS_DATA_TESTS_H_ +#define _TEST_S008_ITS_DATA_TESTS_H_ + +#include "val_internal_trusted_storage.h" + +#define SST_FUNCTION val->its_function +#define psa_sst_uid_t psa_its_uid_t + +typedef struct { + enum its_function_code api; + psa_its_status_t status; +} test_data; + +static const test_data s008_data[] = { +{ + 0, 0 /* This is dummy for index0 */ +}, +{ + VAL_ITS_SET, PSA_ITS_SUCCESS /* Create a valid storage entity with zero flag value */ +}, +{ + VAL_ITS_GET, PSA_ITS_SUCCESS /* Call get API with offset + data_len = total_size */ +}, +{ + 0, 0 /* This is dummy for index3 */ +}, +{ + VAL_ITS_GET, PSA_ITS_SUCCESS /* Call get API with offset + data_len < total_size */ +}, +{ + 0, 0 /* This is dummy for index5 */ +}, +{ + VAL_ITS_GET, PSA_ITS_SUCCESS /* Call get API with offset = total data_size + 1 */ +}, +{ + 0, 0 /* This is dummy for index7 */ +}, +{ + VAL_ITS_GET, PSA_ITS_ERROR_INCORRECT_SIZE /* get API with offset + data_len > total data_size */ +}, +{ + 0, 0 /* This is dummy for index9 */ +}, +{ + VAL_ITS_GET, PSA_ITS_ERROR_INCORRECT_SIZE /* Call get API with invalid data len and offset zero */ +}, +{ + 0, 0 /* This is dummy for index11 */ +}, +{ + VAL_ITS_GET, PSA_ITS_SUCCESS /* Call get API with offset = MAX_UINT32 */ +}, +{ + VAL_ITS_REMOVE, PSA_ITS_SUCCESS /* Remove the storage entity */ +}, +}; +#endif /* _TEST_S008_ITS_DATA_TESTS_H_ */ diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s008/test_ps_data.h b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s008/test_ps_data.h new file mode 100644 index 0000000..2b15d35 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s008/test_ps_data.h @@ -0,0 +1,74 @@ +/** @file + * Copyright (c) 2019, Arm Limited or ps affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ +#ifndef _TEST_S008_PS_DATA_TESTS_H_ +#define _TEST_S008_PS_DATA_TESTS_H_ + +#include "val_protected_storage.h" + +#define SST_FUNCTION val->ps_function +#define psa_sst_uid_t psa_ps_uid_t + +typedef struct { + enum ps_function_code api; + psa_ps_status_t status; +} test_data; + +static const test_data s008_data[] = { +{ + 0, 0 /* This is dummy for index0 */ +}, +{ + VAL_PS_SET, PSA_PS_SUCCESS /* Create a valid storage entity with zero flag value */ +}, +{ + VAL_PS_GET, PSA_PS_SUCCESS /* Call get API with offset + data_len = total_size */ +}, +{ + 0, 0 /* This is dummy for index3 */ +}, +{ + VAL_PS_GET, PSA_PS_SUCCESS /* Call get API with offset + data_len < total_size */ +}, +{ + 0, 0 /* This is dummy for index5 */ +}, +{ + VAL_PS_GET, PSA_PS_SUCCESS/* Call get API with offset = total data_size + 1 */ +}, +{ + 0, 0 /* This is dummy for index7 */ +}, +{ + VAL_PS_GET, PSA_PS_ERROR_INCORRECT_SIZE /* Call get API with offset + data_len > total data_size */ +}, +{ + 0, 0 /* This is dummy for index9 */ +}, +{ + VAL_PS_GET, PSA_PS_ERROR_INCORRECT_SIZE /* Call get API with invalid data len and offset zero */ +}, +{ + 0, 0 /* This is dummy for index11 */ +}, +{ + VAL_PS_GET, PSA_PS_SUCCESS /* Call get API with offset = MAX_UINT32 */ +}, +{ + VAL_PS_REMOVE, PSA_PS_SUCCESS /* Remove the storage entity */ +}, +}; +#endif /* _TEST_S008_PS_DATA_TESTS_H_ */ diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s008/test_s008.c b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s008/test_s008.c new file mode 100644 index 0000000..7a2536e --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s008/test_s008.c @@ -0,0 +1,116 @@ +/** @file + * Copyright (c) 2019, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ + +#include "val_interfaces.h" +#include "val_target.h" +#include "test_s008.h" +#ifdef ITS_TEST +#include "test_its_data.h" +#elif PS_TEST +#include "test_ps_data.h" +#endif + +#define TEST_BUFF_SIZE 20 +#define TEST_MAX_UINT32 0xFFFFFFFF + +client_test_t test_s008_sst_list[] = { + NULL, + psa_sst_valid_offset_success, + psa_sst_invalid_offset_failure, + NULL, +}; + +static psa_sst_uid_t uid = UID_BASE_VALUE + 5; +static uint8_t read_buff[TEST_BUFF_SIZE]; +static uint8_t write_buff[TEST_BUFF_SIZE] = {0x99, 0x01, 0x02, 0x03, 0x04, 0x23, 0xF6, 0x07, 0x08, \ + 0x0D, 0x70, 0xA1, 0xFF, 0xFF, 0x14, 0x73, 0x46, 0x97, 0xE8, 0xDD}; + +int32_t psa_sst_invalid_offset_failure(caller_security_t caller) +{ + uint32_t status, j; + + /* Case where offset = data_size +1 , data_len 0. Also check nothing is returned in read buff*/ + val->print(PRINT_TEST, "[Check 2] Try to access data with varying invalid offset\n", 0); + memset(read_buff, 0, TEST_BUFF_SIZE); + status = SST_FUNCTION(s008_data[6].api, uid, TEST_BUFF_SIZE+1, 0, read_buff); + TEST_ASSERT_NOT_EQUAL(status, s008_data[6].status, TEST_CHECKPOINT_NUM(6)); + for (j = 0; j < TEST_BUFF_SIZE; j++) + { + TEST_ASSERT_EQUAL(read_buff[j], 0x00, TEST_CHECKPOINT_NUM(7)); + } + + /* Case where offset = data_size , data_len= 1 Also check nothing is returned in read buff*/ + status = SST_FUNCTION(s008_data[8].api, uid, TEST_BUFF_SIZE, 1, read_buff); + TEST_ASSERT_EQUAL(status, s008_data[8].status, TEST_CHECKPOINT_NUM(8)); + for (j = 0; j < TEST_BUFF_SIZE; j++) + { + TEST_ASSERT_EQUAL(read_buff[j], 0x00, TEST_CHECKPOINT_NUM(9)); + } + + /* Case where offset = 0 , data_len > data_size Also check nothing is returned in read buff*/ + status = SST_FUNCTION(s008_data[10].api, uid, 0, TEST_BUFF_SIZE+1, read_buff); + TEST_ASSERT_EQUAL(status, s008_data[10].status, TEST_CHECKPOINT_NUM(10)); + for (j = 0; j < TEST_BUFF_SIZE; j++) + { + TEST_ASSERT_EQUAL(read_buff[j], 0x00, TEST_CHECKPOINT_NUM(11)); + } + + /* Try to access data with offset as MAX_UINT32 and length less than buffer size */ + status = SST_FUNCTION(s008_data[12].api, uid, TEST_MAX_UINT32, TEST_BUFF_SIZE/2, read_buff); + TEST_ASSERT_NOT_EQUAL(status, s008_data[12].status, TEST_CHECKPOINT_NUM(12)); + + /* Remove the UID */ + status = SST_FUNCTION(s008_data[13].api, uid); + TEST_ASSERT_EQUAL(status, s008_data[13].status, TEST_CHECKPOINT_NUM(13)); + + return VAL_STATUS_SUCCESS; +} + +int32_t psa_sst_valid_offset_success(caller_security_t caller) +{ + uint32_t status, data_len, offset = TEST_BUFF_SIZE; + + /* Set data for UID */ + status = SST_FUNCTION(s008_data[1].api, uid, TEST_BUFF_SIZE, write_buff, 0); + TEST_ASSERT_EQUAL(status, s008_data[1].status, TEST_CHECKPOINT_NUM(1)); + + /* Case where offset + datalen = data_size */ + val->print(PRINT_TEST, "[Check 1] Try to access data with varying valid offset\n", 0); + while (offset > 0) + { + data_len = TEST_BUFF_SIZE - offset; + memset(read_buff, 0, TEST_BUFF_SIZE); + status = SST_FUNCTION(s008_data[2].api, uid, offset, data_len, read_buff); + TEST_ASSERT_EQUAL(status, s008_data[2].status, TEST_CHECKPOINT_NUM(2)); + TEST_ASSERT_MEMCMP(read_buff, write_buff + offset, data_len, TEST_CHECKPOINT_NUM(3)); + offset >>= 1; + } + + offset = TEST_BUFF_SIZE - 2; + data_len = 1; + /* Case where offset + datalen < data_size */ + while (offset > 0) + { + status = SST_FUNCTION(s008_data[4].api, uid, offset, data_len, read_buff); + TEST_ASSERT_EQUAL(status, s008_data[4].status, TEST_CHECKPOINT_NUM(4)); + TEST_ASSERT_MEMCMP(read_buff, write_buff + offset, data_len, TEST_CHECKPOINT_NUM(5)); + offset >>= 1; + data_len <<= 1; + } + + return VAL_STATUS_SUCCESS; +} diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s008/test_s008.h b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s008/test_s008.h new file mode 100644 index 0000000..d036b4a --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s008/test_s008.h @@ -0,0 +1,37 @@ +/** @file + * Copyright (c) 2019, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ +#ifndef _TEST_S008_CLIENT_TESTS_H_ +#define _TEST_S008_CLIENT_TESTS_H_ + +#ifdef ITS_TEST +#define VAL_STORAGE_BASE VAL_INTERNAL_TRUSTED_STORAGE_BASE +#define test_entry CONCAT(test_entry_, s008) +#elif PS_TEST +#define VAL_STORAGE_BASE VAL_PROTECTED_STORAGE_BASE +#define test_entry CONCAT(test_entry_, p008) +#endif +#define val CONCAT(val,test_entry) +#define psa CONCAT(psa,test_entry) + +extern val_api_t *val; +extern psa_api_t *psa; +extern client_test_t test_s008_sst_list[]; + +int32_t psa_sst_valid_offset_success(caller_security_t caller); +int32_t psa_sst_invalid_offset_failure(caller_security_t caller); + +#endif /* _TEST_S008_CLIENT_TESTS_H_ */ diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s009/main.c b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s009/main.c new file mode 100644 index 0000000..74a6ddb --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s009/main.c @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2020, Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "val_interfaces.h" +#include "pal_mbed_os_intf.h" + +#if !defined(MBED_CONF_RTOS_PRESENT) +#error [NOT_SUPPORTED] PSA compliance its test cases require RTOS to run +#else + +#ifdef ITS_TEST +void test_entry_s009(val_api_t *val_api, psa_api_t *psa_api); +#elif PS_TEST +void test_entry_p009(val_api_t *val_api, psa_api_t *psa_api); +#endif + +int main(void) +{ +#ifdef ITS_TEST + test_start(test_entry_s009, COMPLIANCE_TEST_STORAGE); +#elif PS_TEST + test_start(test_entry_p009, COMPLIANCE_TEST_STORAGE); +#endif +} +#endif // !defined(MBED_CONF_RTOS_PRESENT) diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s009/test_entry.c b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s009/test_entry.c new file mode 100644 index 0000000..37883fb --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s009/test_entry.c @@ -0,0 +1,53 @@ +/** @file + * Copyright (c) 2019, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ + +#include "val_interfaces.h" +#include "val_target.h" +#include "test_s009.h" + +#define TEST_NUM VAL_CREATE_TEST_ID(VAL_STORAGE_BASE, 9) +#define TEST_DESC "Invalid Arguments check\n" + +TEST_PUBLISH(TEST_NUM, test_entry); +val_api_t *val = NULL; +psa_api_t *psa = NULL; + +void test_entry(val_api_t *val_api, psa_api_t *psa_api) +{ + int32_t status = VAL_STATUS_SUCCESS; + + val = val_api; + psa = psa_api; + + /* test init */ + val->test_init(TEST_NUM, TEST_DESC, TEST_FIELD(TEST_ISOLATION_L1, WD_HIGH_TIMEOUT)); + if (!IS_TEST_START(val->get_status())) + { + goto test_exit; + } + + /* Execute list of tests available in test[num]_secure_storage_list from Non-secure side*/ + status = val->execute_non_secure_tests(TEST_NUM, test_s009_sst_list, FALSE); + + if (VAL_ERROR(status)) + { + goto test_exit; + } + +test_exit: + val->test_exit(); +} diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s009/test_its_data.h b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s009/test_its_data.h new file mode 100644 index 0000000..80e7fb1 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s009/test_its_data.h @@ -0,0 +1,69 @@ +/** @file + * Copyright (c) 2019, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ +#ifndef _TEST_S009_ITS_DATA_TESTS_H_ +#define _TEST_S009_ITS_DATA_TESTS_H_ + +#include "val_internal_trusted_storage.h" + +#define SST_FUNCTION val->its_function +#define psa_sst_uid_t psa_its_uid_t + +typedef struct { + enum its_function_code api; + psa_its_status_t status; +} test_data; + +static struct psa_its_info_t info; +static const test_data s009_data[] = { +{ + 0, 0 /* This is dummy for index0 */ +}, +{ + VAL_ITS_SET, PSA_ITS_SUCCESS /* Call set API with NULL write buffer and 0 length */ +}, +{ + VAL_ITS_GET_INFO, PSA_ITS_SUCCESS /* Verify UID is created */ +}, +{ + VAL_ITS_GET, PSA_ITS_SUCCESS /* Call get API with NULL write buffer and 0 length */ +}, +{ + VAL_ITS_REMOVE, PSA_ITS_SUCCESS /* Remove the storage entity */ +}, +{ + VAL_ITS_GET_INFO, PSA_ITS_ERROR_UID_NOT_FOUND /* Verify UID is removed */ +}, +{ + VAL_ITS_SET, PSA_ITS_SUCCESS /* Create storage of zero size and valid write buffer */ +}, +{ + VAL_ITS_GET_INFO, PSA_ITS_SUCCESS /* Call get_info API to check data size */ +}, +{ + 0, 0 /* This is dummy for index8 */ +}, +{ + VAL_ITS_GET, PSA_ITS_SUCCESS /* Call get API with 0 length and NULL read buffer */ +}, +{ + VAL_ITS_SET, PSA_ITS_SUCCESS /* Increase the asset size */ +}, +{ + VAL_ITS_REMOVE, PSA_ITS_SUCCESS /* Remove the storage entity */ +}, +}; +#endif /* _TEST_S009_ITS_DATA_TESTS_H_ */ diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s009/test_ps_data.h b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s009/test_ps_data.h new file mode 100644 index 0000000..129bca0 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s009/test_ps_data.h @@ -0,0 +1,69 @@ +/** @file + * Copyright (c) 2019, Arm Limited or ps affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ +#ifndef _TEST_S009_PS_DATA_TESTS_H_ +#define _TEST_S009_PS_DATA_TESTS_H_ + +#include "val_protected_storage.h" + +#define SST_FUNCTION val->ps_function +#define psa_sst_uid_t psa_ps_uid_t + +typedef struct { + enum ps_function_code api; + psa_ps_status_t status; +} test_data; + +static struct psa_ps_info_t info; +static const test_data s009_data[] = { +{ + 0, 0 /* This is dummy for index0 */ +}, +{ + VAL_PS_SET, PSA_PS_SUCCESS /* Call set API with NULL write buffer and 0 length */ +}, +{ + VAL_PS_GET_INFO, PSA_PS_SUCCESS /* Verify UID is created */ +}, +{ + VAL_PS_GET, PSA_PS_SUCCESS /* Call get API with NULL write buffer and 0 length */ +}, +{ + VAL_PS_REMOVE, PSA_PS_SUCCESS /* Remove the storage entity */ +}, +{ + VAL_PS_GET_INFO, PSA_PS_ERROR_UID_NOT_FOUND /* Verify UID is removed */ +}, +{ + VAL_PS_SET, PSA_PS_SUCCESS /* Create storage of zero size and valid write buffer */ +}, +{ + VAL_PS_GET_INFO, PSA_PS_SUCCESS /* Call get_info API to check data size */ +}, +{ + 0, 0 /* This is dummy for index8 */ +}, +{ + VAL_PS_GET, PSA_PS_SUCCESS /* Call get API with 0 length and NULL read buffer */ +}, +{ + VAL_PS_SET, PSA_PS_SUCCESS /* Increase the asset size */ +}, +{ + VAL_PS_REMOVE, PSA_PS_SUCCESS /* Remove the storage entity */ +}, +}; +#endif /* _TEST_S009_PS_DATA_TESTS_H_ */ diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s009/test_s009.c b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s009/test_s009.c new file mode 100644 index 0000000..c54fa02 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s009/test_s009.c @@ -0,0 +1,92 @@ +/** @file + * Copyright (c) 2019, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ + +#include "val_interfaces.h" +#include "val_target.h" +#include "test_s009.h" +#ifdef ITS_TEST +#include "test_its_data.h" +#elif PS_TEST +#include "test_ps_data.h" +#endif + +#define TEST_BUFF_SIZE 20 + +client_test_t test_s009_sst_list[] = { + NULL, + psa_sst_zero_length_check, + NULL, +}; + +static psa_sst_uid_t uid = UID_BASE_VALUE + 5; +static uint8_t write_buff[TEST_BUFF_SIZE] = {0x99, 0x01, 0x02, 0x03, 0x04, 0x23, 0xF6, 0x07, 0x08, \ + 0x0D, 0x70, 0xA1, 0xFF, 0xFF, 0x14, 0x73, 0x46, 0x97, 0xE8, 0xDD}; + +int32_t psa_sst_zero_length_check(caller_security_t caller) +{ + uint32_t status; + + /* Set data for UID with length 0 and NULL pointer */ + val->print(PRINT_TEST, "[Check 1] Call set API with NULL pointer and data length 0\n", 0); + status = SST_FUNCTION(s009_data[1].api, uid, 0, NULL, 0); + TEST_ASSERT_EQUAL(status, s009_data[1].status, TEST_CHECKPOINT_NUM(1)); + + /* Call the get_info function to verify UID created */ + status = SST_FUNCTION(s009_data[2].api, uid, &info); + TEST_ASSERT_EQUAL(status, s009_data[2].status, TEST_CHECKPOINT_NUM(2)); + + /* Call get API with NULL read buffer */ + val->print(PRINT_TEST, "[Check 2] Call get API with NULL read buffer and data length 0\n", 0); + status = SST_FUNCTION(s009_data[3].api, uid, 0, 0, NULL); + TEST_ASSERT_EQUAL(status, s009_data[3].status, TEST_CHECKPOINT_NUM(3)); + + /* Remove the UID */ + val->print(PRINT_TEST, "[Check 3] Remove the UID\n", 0); + status = SST_FUNCTION(s009_data[4].api, uid); + TEST_ASSERT_EQUAL(status, s009_data[4].status, TEST_CHECKPOINT_NUM(4)); + + /* Call the get_info function to verify UID is removed */ + val->print(PRINT_TEST, "[Check 4] Call get_info API to verify UID removed\n", 0); + status = SST_FUNCTION(s009_data[5].api, uid, &info); + TEST_ASSERT_EQUAL(status, s009_data[5].status, TEST_CHECKPOINT_NUM(5)); + + /* Create UID with length 0 and valid write buffer */ + val->print(PRINT_TEST, "[Check 5] Create UID with zero data_len and valid write buffer\n", 0); + status = SST_FUNCTION(s009_data[6].api, uid, 0, write_buff, 0); + TEST_ASSERT_EQUAL(status, s009_data[6].status, TEST_CHECKPOINT_NUM(6)); + + /* Call the get_info function and match the attributes */ + status = SST_FUNCTION(s009_data[7].api, uid, &info); + TEST_ASSERT_EQUAL(status, s009_data[7].status, TEST_CHECKPOINT_NUM(7)); + TEST_ASSERT_EQUAL(info.size, 0, TEST_CHECKPOINT_NUM(8)); + + /* Call get API with NULL read buffer and valid UID */ + val->print(PRINT_TEST, "[Check 8] Call get API with NULL read buffer and data length 0\n", 0); + status = SST_FUNCTION(s009_data[9].api, uid, 0, 0, NULL); + TEST_ASSERT_EQUAL(status, s009_data[9].status, TEST_CHECKPOINT_NUM(9)); + + /* Change the length to test_buff_size */ + val->print(PRINT_TEST, "[Check 9] Increase the length\n", 0); + status = SST_FUNCTION(s009_data[10].api, uid, TEST_BUFF_SIZE, write_buff, 0); + TEST_ASSERT_EQUAL(status, s009_data[10].status, TEST_CHECKPOINT_NUM(10)); + + /* Remove the UID */ + status = SST_FUNCTION(s009_data[11].api, uid); + TEST_ASSERT_EQUAL(status, s009_data[11].status, TEST_CHECKPOINT_NUM(11)); + + return VAL_STATUS_SUCCESS; +} diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s009/test_s009.h b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s009/test_s009.h new file mode 100644 index 0000000..49a5de0 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s009/test_s009.h @@ -0,0 +1,36 @@ +/** @file + * Copyright (c) 2019, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ +#ifndef _TEST_S009_CLIENT_TESTS_H_ +#define _TEST_S009_CLIENT_TESTS_H_ + +#ifdef ITS_TEST +#define VAL_STORAGE_BASE VAL_INTERNAL_TRUSTED_STORAGE_BASE +#define test_entry CONCAT(test_entry_, s009) +#elif PS_TEST +#define VAL_STORAGE_BASE VAL_PROTECTED_STORAGE_BASE +#define test_entry CONCAT(test_entry_, p009) +#endif +#define val CONCAT(val,test_entry) +#define psa CONCAT(psa,test_entry) + +extern val_api_t *val; +extern psa_api_t *psa; +extern client_test_t test_s009_sst_list[]; + +int32_t psa_sst_zero_length_check(caller_security_t caller); + +#endif /* _TEST_S009_CLIENT_TESTS_H_ */ diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s010/main.c b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s010/main.c new file mode 100644 index 0000000..c9f0728 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s010/main.c @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2020, Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "val_interfaces.h" +#include "pal_mbed_os_intf.h" + +#if !defined(MBED_CONF_RTOS_PRESENT) +#error [NOT_SUPPORTED] PSA compliance its test cases require RTOS to run +#else + +#ifdef ITS_TEST +void test_entry_s010(val_api_t *val_api, psa_api_t *psa_api); +#elif PS_TEST +void test_entry_p010(val_api_t *val_api, psa_api_t *psa_api); +#endif + +int main(void) +{ +#ifdef ITS_TEST + test_start(test_entry_s010, COMPLIANCE_TEST_STORAGE); +#elif PS_TEST + test_start(test_entry_p010, COMPLIANCE_TEST_STORAGE); +#endif +} +#endif // !defined(MBED_CONF_RTOS_PRESENT) diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s010/test_entry.c b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s010/test_entry.c new file mode 100644 index 0000000..82623c6 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s010/test_entry.c @@ -0,0 +1,53 @@ +/** @file + * Copyright (c) 2019, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ + +#include "val_interfaces.h" +#include "val_target.h" +#include "test_s010.h" + +#define TEST_NUM VAL_CREATE_TEST_ID(VAL_STORAGE_BASE, 10) +#define TEST_DESC "UID value zero check\n" + +TEST_PUBLISH(TEST_NUM, test_entry); +val_api_t *val = NULL; +psa_api_t *psa = NULL; + +void test_entry(val_api_t *val_api, psa_api_t *psa_api) +{ + int32_t status = VAL_STATUS_SUCCESS; + + val = val_api; + psa = psa_api; + + /* test init */ + val->test_init(TEST_NUM, TEST_DESC, TEST_FIELD(TEST_ISOLATION_L1, WD_HIGH_TIMEOUT)); + if (!IS_TEST_START(val->get_status())) + { + goto test_exit; + } + + /* Execute list of tests available in test[num]_secure_storage_list from Non-secure side*/ + status = val->execute_non_secure_tests(TEST_NUM, test_s010_sst_list, FALSE); + + if (VAL_ERROR(status)) + { + goto test_exit; + } + +test_exit: + val->test_exit(); +} diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s010/test_its_data.h b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s010/test_its_data.h new file mode 100644 index 0000000..7b1b6d3 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s010/test_its_data.h @@ -0,0 +1,35 @@ +/** @file + * Copyright (c) 2019, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ +#ifndef _TEST_S010_ITS_DATA_TESTS_H_ +#define _TEST_S010_ITS_DATA_TESTS_H_ + +#include "val_internal_trusted_storage.h" + +#define SST_FUNCTION val->its_function +#define psa_sst_uid_t psa_its_uid_t + +typedef struct { + enum its_function_code api; + psa_its_status_t status; +} test_data; + +static const test_data s010_data[] = { +{ + VAL_ITS_SET, PSA_ITS_SUCCESS /* Create with UID value zero should fail */ +}, +}; +#endif /* _TEST_S010_ITS_DATA_TESTS_H_ */ diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s010/test_ps_data.h b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s010/test_ps_data.h new file mode 100644 index 0000000..e88ed9b --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s010/test_ps_data.h @@ -0,0 +1,35 @@ +/** @file + * Copyright (c) 2019, Arm Limited or ps affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ +#ifndef _TEST_S010_PS_DATA_TESTS_H_ +#define _TEST_S010_PS_DATA_TESTS_H_ + +#include "val_protected_storage.h" + +#define SST_FUNCTION val->ps_function +#define psa_sst_uid_t psa_ps_uid_t + +typedef struct { + enum ps_function_code api; + psa_ps_status_t status; +} test_data; + +static const test_data s010_data[] = { +{ + VAL_PS_SET, PSA_PS_SUCCESS /* Create with UID value zero should fail */ +}, +}; +#endif /* _TEST_S010_PS_DATA_TESTS_H_ */ diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s010/test_s010.c b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s010/test_s010.c new file mode 100644 index 0000000..380c069 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s010/test_s010.c @@ -0,0 +1,49 @@ +/** @file + * Copyright (c) 2019, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ + +#include "val_interfaces.h" +#include "val_target.h" +#include "test_s010.h" +#ifdef ITS_TEST +#include "test_its_data.h" +#elif PS_TEST +#include "test_ps_data.h" +#endif + +#define TEST_BUFF_SIZE 1 + +client_test_t test_s010_sst_list[] = { + NULL, + psa_sst_uid_value_zero_check, + NULL, +}; + +static uint8_t write_buff[TEST_BUFF_SIZE] = {0xFF}; + +int32_t psa_sst_uid_value_zero_check(caller_security_t caller) +{ + int32_t status; + psa_sst_uid_t uid = 0; + + /* Set with UID value zero should fail */ + val->print(PRINT_TEST, "[Check 1] Creating storage with UID 0 should fail\n", 0 ); + status = SST_FUNCTION(s010_data[0].api, uid, TEST_BUFF_SIZE, write_buff, 0); + TEST_ASSERT_NOT_EQUAL(status, s010_data[0].status, TEST_CHECKPOINT_NUM(1)); + + return VAL_STATUS_SUCCESS; +} + diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s010/test_s010.h b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s010/test_s010.h new file mode 100644 index 0000000..35dfb7c --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/compliance_its/test_s010/test_s010.h @@ -0,0 +1,35 @@ +/** @file + * Copyright (c) 2019, Arm Limited or its affiliates. All rights reserved. + * SPDX-License-Identifier : Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +**/ +#ifndef _TEST_S010_CLIENT_TESTS_H_ +#define _TEST_S010_CLIENT_TESTS_H_ + +#ifdef ITS_TEST +#define VAL_STORAGE_BASE VAL_INTERNAL_TRUSTED_STORAGE_BASE +#define test_entry CONCAT(test_entry_, s010) +#elif PS_TEST +#define VAL_STORAGE_BASE VAL_PROTECTED_STORAGE_BASE +#define test_entry CONCAT(test_entry_, p010) +#endif +#define val CONCAT(val,test_entry) +#define psa CONCAT(psa,test_entry) + +extern val_api_t *val; +extern psa_api_t *psa; +extern client_test_t test_s010_sst_list[]; + +int32_t psa_sst_uid_value_zero_check(caller_security_t caller); +#endif /* _TEST_S010_CLIENT_TESTS_H_ */ diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/crypto_init/main.cpp b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/crypto_init/main.cpp new file mode 100644 index 0000000..c585449 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/crypto_init/main.cpp @@ -0,0 +1,116 @@ +/* +* Copyright (c) 2018 ARM Limited. All rights reserved. +* +* SPDX-License-Identifier: Apache-2.0 +* +* Licensed under the Apache License, Version 2.0 (the License); you may +* not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an AS IS BASIS, WITHOUT +* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include "psa/crypto.h" + +#if ((!defined(TARGET_PSA)) || (!defined(MBEDTLS_PSA_CRYPTO_C))) +#error [NOT_SUPPORTED] Mbed Crypto is OFF - skipping. +#else + +#include "greentea-client/test_env.h" +#include "unity/unity.h" +#include "utest/utest.h" +#include "entropy.h" +#include "entropy_poll.h" + +#define TEST_RANDOM_SIZE 64 + +#if !defined(MAX) +#define MAX(a,b) (((a)>(b))?(a):(b)) +#endif + +/* Calculating the minimum allowed entropy size in bytes */ +#define MBEDTLS_PSA_INJECT_ENTROPY_MIN_SIZE \ + MAX(MBEDTLS_ENTROPY_MIN_PLATFORM, MBEDTLS_ENTROPY_BLOCK_SIZE) + +using namespace utest::v1; + +utest::v1::status_t greentea_test_setup(const size_t number_of_cases) +{ + GREENTEA_SETUP(60, "default_auto"); + return greentea_test_setup_handler(number_of_cases); +} + +static void check_multi_crypto_init_deinit() +{ +#if !defined(COMPONENT_PSA_SRV_IPC) + TEST_SKIP(); +#endif + uint8_t output[TEST_RANDOM_SIZE] = {0}; + + psa_status_t status = psa_crypto_init(); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + status = psa_crypto_init(); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + status = psa_generate_random(output, sizeof(output)); + TEST_ASSERT_NOT_EQUAL(PSA_ERROR_BAD_STATE, status); + + mbedtls_psa_crypto_free(); + status = psa_generate_random(output, sizeof(output)); + TEST_ASSERT_NOT_EQUAL(PSA_ERROR_BAD_STATE, status); + + mbedtls_psa_crypto_free(); + status = psa_generate_random(output, sizeof(output)); + TEST_ASSERT_EQUAL(PSA_ERROR_BAD_STATE, status); +} + +static void check_crypto_init_deinit() +{ + psa_status_t status; + uint8_t output[TEST_RANDOM_SIZE] = {0}; + + // Should fail as init is required first + status = psa_generate_random(output, sizeof(output)); + TEST_ASSERT_EQUAL(PSA_ERROR_BAD_STATE, status); + + status = psa_crypto_init(); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + status = psa_generate_random(output, sizeof(output)); + TEST_ASSERT_NOT_EQUAL(PSA_ERROR_BAD_STATE, status); + + mbedtls_psa_crypto_free(); + status = psa_generate_random(output, sizeof(output)); + TEST_ASSERT_EQUAL(PSA_ERROR_BAD_STATE, status); +} + +Case cases[] = { + Case("PSA crypto-init De-init", check_crypto_init_deinit), + Case("PSA crypto- multiple init De-init", check_multi_crypto_init_deinit), +}; + +Specification specification(greentea_test_setup, cases, greentea_test_teardown_handler); + +int main() +{ +#if (defined(COMPONENT_PSA_SRV_IPC) || defined(MBEDTLS_ENTROPY_NV_SEED)) + uint8_t seed[MBEDTLS_PSA_INJECT_ENTROPY_MIN_SIZE] = {0}; + /* inject some a seed for test*/ + for (int i = 0; i < MBEDTLS_PSA_INJECT_ENTROPY_MIN_SIZE; ++i) { + seed[i] = i; + } + + /* don't really care if this succeed this is just to make crypto init pass*/ + mbedtls_psa_inject_entropy(seed, MBEDTLS_PSA_INJECT_ENTROPY_MIN_SIZE); +#endif + return !Harness::run(specification); +} + +#endif // ((!defined(TARGET_PSA)) || (!defined(MBEDTLS_PSA_CRYPTO_C))) diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/entropy_inject/main.cpp b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/entropy_inject/main.cpp new file mode 100644 index 0000000..0098e8e --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/entropy_inject/main.cpp @@ -0,0 +1,187 @@ +/* +* Copyright (c) 2018 ARM Limited. All rights reserved. +* +* SPDX-License-Identifier: Apache-2.0 +* +* Licensed under the Apache License, Version 2.0 (the License); you may +* not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an AS IS BASIS, WITHOUT +* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#if ((!defined(TARGET_PSA) || (!defined(COMPONENT_PSA_SRV_IPC)) && !defined(MBEDTLS_ENTROPY_NV_SEED))) +#error [NOT_SUPPORTED] PSA entropy injection tests can run only on PSA-enabled targets. +#else + +#include "greentea-client/test_env.h" +#include "unity/unity.h" +#include "utest/utest.h" +#include "psa/internal_trusted_storage.h" +#include "psa/lifecycle.h" +#include "entropy.h" +#include "entropy_poll.h" +#include "psa/crypto.h" +#include + +/* MAX value support macro */ +#if !defined(MAX) +#define MAX(a,b) (((a)>(b))?(a):(b)) +#endif + +/* Calculating the minimum allowed entropy size in bytes */ +#define MBEDTLS_PSA_INJECT_ENTROPY_MIN_SIZE \ + MAX(MBEDTLS_ENTROPY_MIN_PLATFORM, MBEDTLS_ENTROPY_BLOCK_SIZE) + +using namespace utest::v1; + +uint8_t seed[MBEDTLS_ENTROPY_MAX_SEED_SIZE + 2] = {0}; +bool skip_tests = false; + +void validate_entropy_seed_injection(int seed_length_a, + int expected_status_a, + int seed_length_b, + int expected_status_b) +{ + psa_status_t status; + uint8_t output[32] = { 0 }; + uint8_t zeros[32] = { 0 }; + int memcmp_res = 0; + status = mbedtls_psa_inject_entropy(seed, seed_length_a); + TEST_ASSERT_EQUAL_INT(expected_status_a, status); + + status = mbedtls_psa_inject_entropy(seed, seed_length_b); + TEST_ASSERT_EQUAL_INT(expected_status_b, status); + + status = psa_crypto_init(); + TEST_ASSERT_EQUAL_INT(PSA_SUCCESS, status); + + status = psa_generate_random(output, sizeof(output)); + TEST_ASSERT_EQUAL_INT(PSA_SUCCESS, status); + + memcmp_res = memcmp(output, zeros, sizeof(output)); + TEST_ASSERT_NOT_EQUAL(0, memcmp_res); +} + +void run_entropy_inject_with_crypto_init() +{ + psa_status_t status; + status = psa_crypto_init(); + TEST_ASSERT_EQUAL_INT(PSA_ERROR_INSUFFICIENT_ENTROPY, status); + + status = mbedtls_psa_inject_entropy(seed, MBEDTLS_PSA_INJECT_ENTROPY_MIN_SIZE); + TEST_ASSERT_EQUAL_INT(PSA_SUCCESS, status); + + status = psa_crypto_init(); + TEST_ASSERT_EQUAL_INT(PSA_SUCCESS, status); + + status = mbedtls_psa_inject_entropy(seed, MBEDTLS_PSA_INJECT_ENTROPY_MIN_SIZE); + TEST_ASSERT_EQUAL_INT(PSA_ERROR_NOT_PERMITTED, status); + + mbedtls_psa_crypto_free(); + /* The seed is written by nv_seed callback functions therefore the injection will fail */ + status = mbedtls_psa_inject_entropy(seed, MBEDTLS_PSA_INJECT_ENTROPY_MIN_SIZE); + TEST_ASSERT_EQUAL_INT(PSA_ERROR_NOT_PERMITTED, status); +} + + +utest::v1::status_t greentea_test_setup(const size_t number_of_cases) +{ + GREENTEA_SETUP(60, "default_auto"); + + /* fill seed in some data */ + for (size_t i = 0; i < sizeof(seed); ++i) { + seed[i] = i; + } + + psa_status_t status = mbed_psa_reboot_and_request_new_security_state(PSA_LIFECYCLE_ASSEMBLY_AND_TEST); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + if (mbedtls_psa_inject_entropy(seed, MBEDTLS_ENTROPY_MAX_SEED_SIZE) == PSA_ERROR_NOT_SUPPORTED) { + skip_tests = true; + } + + return greentea_test_setup_handler(number_of_cases); +} + +static void injection_small_good() +{ + TEST_SKIP_UNLESS(!skip_tests); + validate_entropy_seed_injection( + MBEDTLS_PSA_INJECT_ENTROPY_MIN_SIZE, PSA_SUCCESS, + MBEDTLS_PSA_INJECT_ENTROPY_MIN_SIZE, PSA_ERROR_NOT_PERMITTED); +} + +static void injection_big_good() +{ + TEST_SKIP_UNLESS(!skip_tests); + validate_entropy_seed_injection( + MBEDTLS_ENTROPY_MAX_SEED_SIZE, PSA_SUCCESS, + MBEDTLS_ENTROPY_MAX_SEED_SIZE, PSA_ERROR_NOT_PERMITTED); +} + +static void injection_too_small() +{ + TEST_SKIP_UNLESS(!skip_tests); + validate_entropy_seed_injection( + (MBEDTLS_ENTROPY_MIN_PLATFORM - 1), PSA_ERROR_INVALID_ARGUMENT, + MBEDTLS_PSA_INJECT_ENTROPY_MIN_SIZE, PSA_SUCCESS); +} + +static void injection_too_big() +{ + TEST_SKIP_UNLESS(!skip_tests); + validate_entropy_seed_injection( + (MBEDTLS_ENTROPY_MAX_SEED_SIZE + 1), PSA_ERROR_INVALID_ARGUMENT, + MBEDTLS_ENTROPY_MAX_SEED_SIZE, PSA_SUCCESS); +} + +static void injection_and_init_deinit() +{ + TEST_SKIP_UNLESS(!skip_tests); + run_entropy_inject_with_crypto_init(); +} + + + +/***************************************************************************************/ + +utest::v1::status_t case_teardown_handler(const Case *const source, const size_t passed, const size_t failed, const failure_t reason) +{ + psa_status_t status; + status = mbed_psa_reboot_and_request_new_security_state(PSA_LIFECYCLE_ASSEMBLY_AND_TEST); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + mbedtls_psa_crypto_free(); + return greentea_case_teardown_handler(source, passed, failed, reason); +} + +utest::v1::status_t case_setup_handler(const Case *const source, const size_t index_of_case) +{ + psa_status_t status; + status = mbed_psa_reboot_and_request_new_security_state(PSA_LIFECYCLE_ASSEMBLY_AND_TEST); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + return greentea_case_setup_handler(source, index_of_case); +} + +Case cases[] = { + Case("PSA entropy injection small good", case_setup_handler, injection_small_good, case_teardown_handler), + Case("PSA entropy injection big good", case_setup_handler, injection_big_good, case_teardown_handler), + Case("PSA entropy injection too big", case_setup_handler, injection_too_big, case_teardown_handler), + Case("PSA entropy injection too small", case_setup_handler, injection_too_small, case_teardown_handler), + Case("PSA entropy injection before and after init", case_setup_handler, injection_and_init_deinit, case_teardown_handler), +}; + +Specification specification(greentea_test_setup, cases, greentea_test_teardown_handler); + +int main() +{ + return !Harness::run(specification); +} + +#endif // ((!defined(TARGET_PSA) || (!defined(COMPONENT_PSA_SRV_IPC)) && !defined(MBEDTLS_ENTROPY_NV_SEED))) diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/its_ps/main.cpp b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/its_ps/main.cpp new file mode 100644 index 0000000..ee2c510 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/TESTS/its_ps/main.cpp @@ -0,0 +1,251 @@ +/* +* Copyright (c) 2019 ARM Limited. All rights reserved. +* +* SPDX-License-Identifier: Apache-2.0 +* +* Licensed under the Apache License, Version 2.0 (the License); you may +* not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an AS IS BASIS, WITHOUT +* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#if !defined(MBED_CONF_RTOS_PRESENT) +#error [NOT_SUPPORTED] ITS/PS test cases require RTOS to run. +#else + +#ifndef TARGET_PSA +#error [NOT_SUPPORTED] ITS/PS tests can run only on PSA-enabled targets. +#else + +#include "greentea-client/test_env.h" +#include "unity/unity.h" +#include "utest/utest.h" +#include "psa/error.h" +#include "psa/storage_common.h" +#include "psa/internal_trusted_storage.h" +#include "psa/protected_storage.h" +#include "psa/lifecycle.h" +#include "KVMap.h" +#include "KVStore.h" +#include "kv_config.h" +#include "psa_storage_common_impl.h" +#include "DeviceKey.h" + +using namespace utest::v1; +using namespace mbed; + +#define TEST_BUFF_SIZE 16 +#define STR_EXPAND(tok) #tok + +typedef enum { + its, + ps +} storage_type_t; + +extern "C" psa_status_t psa_ps_reset(); + +static psa_status_t set_func(storage_type_t stype, psa_storage_uid_t uid, size_t data_length, + const void *p_data, psa_storage_create_flags_t create_flags) +{ + return (stype == its) ? + psa_its_set(uid, data_length, p_data, create_flags) : + psa_ps_set(uid, data_length, p_data, create_flags); +} + +static psa_status_t get_func(storage_type_t stype, psa_storage_uid_t uid, size_t data_offset, + size_t data_length, void *p_data, size_t *actual_length) +{ + return (stype == its) ? + psa_its_get(uid, data_offset, data_length, p_data, actual_length) : + psa_ps_get(uid, data_offset, data_length, p_data, actual_length); +} + +static psa_status_t get_info_func(storage_type_t stype, psa_storage_uid_t uid, + struct psa_storage_info_t *p_info) +{ + return (stype == its) ? + psa_its_get_info(uid, p_info) : + psa_ps_get_info(uid, p_info); +} + +static psa_status_t remove_func(storage_type_t stype, psa_storage_uid_t uid) +{ + return (stype == its) ? + psa_its_remove(uid) : + psa_ps_remove(uid); +} + + +template +void pits_ps_test() +{ + psa_status_t status = PSA_SUCCESS; + uint8_t write_buff[TEST_BUFF_SIZE] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F}; + uint8_t read_buff[TEST_BUFF_SIZE] = {0}; + size_t actual_size; + psa_storage_create_flags_t flags; + struct psa_storage_info_t info = {0, PSA_STORAGE_FLAG_WRITE_ONCE}; + memset(read_buff, 0, TEST_BUFF_SIZE); + + status = get_info_func(stype, 5, &info); + TEST_ASSERT_EQUAL(PSA_ERROR_DOES_NOT_EXIST, status); + + status = set_func(stype, 5, TEST_BUFF_SIZE, write_buff, 0); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + status = get_info_func(stype, 5, &info); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + TEST_ASSERT_EQUAL(TEST_BUFF_SIZE, info.size); + TEST_ASSERT_EQUAL(0, info.flags); + + status = get_func(stype, 5, 0, TEST_BUFF_SIZE, read_buff, &actual_size); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + TEST_ASSERT_EQUAL_MEMORY(write_buff, read_buff, TEST_BUFF_SIZE); + + memset(read_buff, 0, TEST_BUFF_SIZE); + status = get_func(stype, 5, 1, TEST_BUFF_SIZE, read_buff, &actual_size); + TEST_ASSERT_NOT_EQUAL(PSA_SUCCESS, status); + + status = get_func(stype, 5, 1, TEST_BUFF_SIZE - 1, read_buff, &actual_size); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + TEST_ASSERT_EQUAL_MEMORY(write_buff + 1, read_buff, TEST_BUFF_SIZE - 1); + + status = remove_func(stype, 5); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + status = get_info_func(stype, 5, &info); + TEST_ASSERT_EQUAL(PSA_ERROR_DOES_NOT_EXIST, status); + + if (stype == its) { + return; + } + + mbed::KVMap &kv_map = mbed::KVMap::get_instance(); + mbed::KVStore *kvstore = kv_map.get_main_kv_instance(STR_EXPAND(MBED_CONF_STORAGE_DEFAULT_KV)); + uint32_t kv_get_flags; + + flags = PSA_STORAGE_FLAG_NO_REPLAY_PROTECTION; + status = set_func(stype, 6, TEST_BUFF_SIZE, write_buff, flags); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + status = get_info_func(stype, 6, &info); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + TEST_ASSERT_EQUAL(flags, info.flags); + + status = psa_storage_get_info_impl(kvstore, 1, 6, &info, &kv_get_flags); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + TEST_ASSERT_EQUAL(kv_get_flags, mbed::KVStore::REQUIRE_CONFIDENTIALITY_FLAG); + + flags = PSA_STORAGE_FLAG_NO_REPLAY_PROTECTION | PSA_STORAGE_FLAG_NO_CONFIDENTIALITY | PSA_STORAGE_FLAG_WRITE_ONCE; + status = set_func(stype, 6, TEST_BUFF_SIZE, write_buff, flags); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + status = get_info_func(stype, 6, &info); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + TEST_ASSERT_EQUAL(flags, info.flags); + + status = psa_storage_get_info_impl(kvstore, 1, 6, &info, &kv_get_flags); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + TEST_ASSERT_EQUAL(kv_get_flags, mbed::KVStore::WRITE_ONCE_FLAG); +} + +template +void pits_ps_write_once_test() +{ + psa_status_t status = PSA_SUCCESS; + uint8_t write_buff[TEST_BUFF_SIZE] = {0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00}; + uint8_t read_buff[TEST_BUFF_SIZE] = {0}; + size_t actual_size; + struct psa_storage_info_t info = {0, 0}; + + status = get_info_func(stype, 5, &info); + TEST_ASSERT_EQUAL(PSA_ERROR_DOES_NOT_EXIST, status); + + status = set_func(stype, 5, TEST_BUFF_SIZE, write_buff, PSA_STORAGE_FLAG_WRITE_ONCE); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + + info.size = 0; + info.flags = PSA_STORAGE_FLAG_WRITE_ONCE; + status = get_info_func(stype, 5, &info); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + TEST_ASSERT_EQUAL(TEST_BUFF_SIZE, info.size); + TEST_ASSERT_EQUAL(PSA_STORAGE_FLAG_WRITE_ONCE, info.flags); + + status = get_func(stype, 5, 0, TEST_BUFF_SIZE, read_buff, &actual_size); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + TEST_ASSERT_EQUAL(TEST_BUFF_SIZE, actual_size); + TEST_ASSERT_EQUAL_MEMORY(write_buff, read_buff, TEST_BUFF_SIZE); + + status = set_func(stype, 5, TEST_BUFF_SIZE, write_buff, PSA_STORAGE_FLAG_WRITE_ONCE); + TEST_ASSERT_EQUAL(PSA_ERROR_NOT_PERMITTED, status); + + status = set_func(stype, 5, TEST_BUFF_SIZE, write_buff, 0); + TEST_ASSERT_EQUAL(PSA_ERROR_NOT_PERMITTED, status); + + status = remove_func(stype, 5); + TEST_ASSERT_EQUAL(PSA_ERROR_NOT_PERMITTED, status); + + info.size = 0; + info.flags = PSA_STORAGE_FLAG_WRITE_ONCE; + status = get_info_func(stype, 5, &info); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + TEST_ASSERT_EQUAL(TEST_BUFF_SIZE, info.size); + TEST_ASSERT_EQUAL(PSA_STORAGE_FLAG_WRITE_ONCE, info.flags); +} + +utest::v1::status_t case_its_teardown_handler(const Case *const source, const size_t passed, const size_t failed, const failure_t reason) +{ + psa_status_t status; + status = mbed_psa_reboot_and_request_new_security_state(PSA_LIFECYCLE_ASSEMBLY_AND_TEST); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + return greentea_case_teardown_handler(source, passed, failed, reason); +} + +template +utest::v1::status_t case_its_setup_handler(const Case *const source, const size_t index_of_case) +{ + psa_status_t status; + if (stype == its) { + status = mbed_psa_reboot_and_request_new_security_state(PSA_LIFECYCLE_ASSEMBLY_AND_TEST); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + } else { + status = psa_ps_reset(); + TEST_ASSERT_EQUAL(PSA_SUCCESS, status); + } +#if DEVICEKEY_ENABLED + DeviceKey::get_instance().generate_root_of_trust(); +#endif + return greentea_case_setup_handler(source, index_of_case); +} + +Case cases[] = { + Case("PSA prot internal storage - Basic", case_its_setup_handler, pits_ps_test, case_its_teardown_handler), + Case("PSA prot internal storage - Write-once", case_its_setup_handler, pits_ps_write_once_test, case_its_teardown_handler), +#if COMPONENT_FLASHIAP + Case("PSA protected storage - Basic", case_its_setup_handler, pits_ps_test), + Case("PSA protected storage - Write-once", case_its_setup_handler, pits_ps_write_once_test) +#endif +}; + +utest::v1::status_t greentea_test_setup(const size_t number_of_cases) +{ + GREENTEA_SETUP(60, "default_auto"); + return greentea_test_setup_handler(number_of_cases); +} + +Specification specification(greentea_test_setup, cases, greentea_test_teardown_handler); + +int main() +{ + return !Harness::run(specification); +} + +#endif // TARGET_PSA +#endif // !defined(MBED_CONF_RTOS_PRESENT) diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/inc/psa/client.h b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/inc/psa/client.h new file mode 100644 index 0000000..effc0ce --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/inc/psa/client.h @@ -0,0 +1,57 @@ +/* Copyright (c) 2017-2018 ARM Limited + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#if defined(TARGET_TFM) +#include "interface/include/psa_client.h" +#else + +#ifndef __MBED_OS_DEFAULT_PSA_CLIENT_API_H__ +#define __MBED_OS_DEFAULT_PSA_CLIENT_API_H__ + +#include +#include "psa/error.h" + +#if !defined(UINT32_MAX) +#define UINT32_MAX ((uint32_t)-1) +#endif + +#if !defined(INT32_MIN) +#define INT32_MIN (-0x7fffffff - 1) +#endif + +#define PSA_FRAMEWORK_VERSION (0x0100) /**< Version of the PSA Framework API. */ +#define PSA_VERSION_NONE (0L) /**< Identifier for an unimplemented Root of Trust (RoT) Service. */ +#define PSA_CONNECTION_REFUSED (INT32_MIN + 1) /**< The return value from psa_connect() if the RoT Service or SPM was unable to establish a connection.*/ +#define PSA_CONNECTION_BUSY (INT32_MIN + 2) /**< The return value from psa_connect() if the RoT Service rejects the connection for a transient reason.*/ +#define PSA_DROP_CONNECTION (INT32_MIN) /**< The result code in a call to psa_reply() to indicate a nonrecoverable error in the client.*/ +#define PSA_NULL_HANDLE ((psa_handle_t)0) /**< Denotes an invalid handle.*/ + +typedef int32_t psa_handle_t; + +typedef struct psa_invec { + const void *base; /**< Starting address of the buffer.*/ + size_t len; /**< Length in bytes of the buffer.*/ +} psa_invec; + + +typedef struct psa_outvec { + void *base; /**< Starting address of the buffer.*/ + size_t len; /**< Length in bytes of the buffer.*/ +} psa_outvec; + +#endif // __MBED_OS_DEFAULT_PSA_CLIENT_API_H__ +#endif diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/inc/psa/error.h b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/inc/psa/error.h new file mode 100644 index 0000000..ba0e0e3 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/inc/psa/error.h @@ -0,0 +1,56 @@ +/* +* Copyright (c) 2019 ARM Limited. All rights reserved. +* +* SPDX-License-Identifier: Apache-2.0 +* +* Licensed under the Apache License, Version 2.0 (the License); you may +* not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an AS IS BASIS, WITHOUT +* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +/* psa/error.h +Standard error codes for the SPM and RoT Services +As defined in PSA Firmware Framework v1.0 +*/ + +#ifndef __PSA_ERROR__ +#define __PSA_ERROR__ + +#include +#include + +typedef int32_t psa_status_t; + +#define PSA_SUCCESS ((psa_status_t)0) + +#define PSA_ERROR_PROGRAMMER_ERROR ((psa_status_t)-129) +#define PSA_ERROR_CONNECTION_REFUSED ((psa_status_t)-130) +#define PSA_ERROR_CONNECTION_BUSY ((psa_status_t)-131) +#define PSA_ERROR_GENERIC_ERROR ((psa_status_t)-132) +#define PSA_ERROR_NOT_PERMITTED ((psa_status_t)-133) +#define PSA_ERROR_NOT_SUPPORTED ((psa_status_t)-134) +#define PSA_ERROR_INVALID_ARGUMENT ((psa_status_t)-135) +#define PSA_ERROR_INVALID_HANDLE ((psa_status_t)-136) +#define PSA_ERROR_BAD_STATE ((psa_status_t)-137) +#define PSA_ERROR_BUFFER_TOO_SMALL ((psa_status_t)-138) +#define PSA_ERROR_ALREADY_EXISTS ((psa_status_t)-139) +#define PSA_ERROR_DOES_NOT_EXIST ((psa_status_t)-140) +#define PSA_ERROR_INSUFFICIENT_MEMORY ((psa_status_t)-141) +#define PSA_ERROR_INSUFFICIENT_STORAGE ((psa_status_t)-142) +#define PSA_ERROR_INSUFFICIENT_DATA ((psa_status_t)-143) +#define PSA_ERROR_SERVICE_FAILURE ((psa_status_t)-144) +#define PSA_ERROR_COMMUNICATION_FAILURE ((psa_status_t)-145) +#define PSA_ERROR_STORAGE_FAILURE ((psa_status_t)-146) +#define PSA_ERROR_HARDWARE_FAILURE ((psa_status_t)-147) +#define PSA_ERROR_INVALID_SIGNATURE ((psa_status_t)-149) +#define PSA_ERROR_DATA_CORRUPT ((psa_status_t)-152) + +#endif // __PSA_ERROR__ diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/inc/psa/internal_trusted_storage.h b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/inc/psa/internal_trusted_storage.h new file mode 100644 index 0000000..7b3b6a9 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/inc/psa/internal_trusted_storage.h @@ -0,0 +1,23 @@ +/* Copyright (c) 2017-2018 ARM Limited + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __MBED_INTERNAL_TRUSTED_STORAGE_H__ +#define __MBED_INTERNAL_TRUSTED_STORAGE_H__ + +#include "psa_prot_internal_storage.h" + +#endif // __MBED_INTERNAL_TRUSTED_STORAGE_H__ diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/inc/psa/lifecycle.h b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/inc/psa/lifecycle.h new file mode 100644 index 0000000..1afa44f --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/inc/psa/lifecycle.h @@ -0,0 +1,79 @@ +/* Copyright (c) 2018 ARM Limited + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LIFECYCLE_H__ +#define __LIFECYCLE_H__ + +/** @file +@brief This file describes the PSA RoT Lifecycle API +*/ + +#include +#include +#include "mbed_toolchain.h" +#include "psa/error.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define PSA_LIFECYCLE_STATE_MASK (0xff00u) /**< A mask value that extracts the main lifecycle state */ +#define PSA_LIFECYCLE_SUBSTATE_MASK (0x00ffu) /**< A mask value that extracts the IMPLEMENTATION DEFINED lifecycle sub-state */ + +#define PSA_LIFECYCLE_UNKNOWN (0x0000u) /**< State is unknown */ +#define PSA_LIFECYCLE_ASSEMBLY_AND_TEST (0x1000u) /**< Assembly and Test state */ +#define PSA_LIFECYCLE_PSA_ROT_PROVISIONING (0x2000u) /**< PSA RoT Provisioning state */ +#define PSA_LIFECYCLE_SECURED (0x3000u) /**< Secured state */ +#define PSA_LIFECYCLE_NON_PSA_ROT_DEBUG (0x4000u) /**< Non PSA RoT debug state */ +#define PSA_LIFECYCLE_RECOVERABLE_PSA_ROT_DEBUG (0x5000u) /**< Recoverable PSA RoT Debug state */ +#define PSA_LIFECYCLE_DECOMMISSIONED (0x6000u) /**< Decommissioned state */ + +/** \brief Get PSA RoT lifecycle state + * + * \retval The main state and sub-state are encoded as follows:@n + @a version[15:8] – main lifecycle state + @a version[7:0] – IMPLEMENTATION DEFINED sub-state + */ +uint32_t psa_security_lifecycle_state(void); + +/** \brief Request state change + * + * State change requested and the reset the system. + * \note System reset will not be performed when switching from PSA_LIFECYCLE_ASSEMBLY_AND_TEST + * to PSA_LIFECYCLE_ASSEMBLY_AND_TEST. + * + * \note state change to follwing states will delete PSA internal storage: + * - PSA_LIFECYCLE_ASSEMBLY_AND_TEST + * - PSA_LIFECYCLE_PSA_ROT_PROVISIONING + * - PSA_LIFECYCLE_DECOMMISSIONED + */ +psa_status_t mbed_psa_reboot_and_request_new_security_state(uint32_t new_state); + + +/** \brief Resets the system + * + * PSA targets do not allow NSPE to access system power domain. + * This API requests system reset to be carried out by SPE once all critical secure tasks are finished. + */ +MBED_NORETURN void mbed_psa_system_reset(); + +#ifdef __cplusplus +} +#endif + +#endif // __LIFECYCLE_H__ diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/inc/psa/protected_storage.h b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/inc/psa/protected_storage.h new file mode 100644 index 0000000..6b299a3 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/inc/psa/protected_storage.h @@ -0,0 +1,202 @@ +/* Copyright (C) 2019, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** @file +@brief This file describes the PSA Protected Storage API +*/ + +#ifndef __PSA_PROTECTED_STORAGE_H__ +#define __PSA_PROTECTED_STORAGE_H__ + +#include +#include + +#include "psa/error.h" +#include "psa/storage_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define PSA_PS_API_VERSION_MAJOR 1 /**< The major version number of the PSA PS API. It will be incremented on significant updates that may include breaking changes */ +#define PSA_PS_API_VERSION_MINOR 1 /**< The minor version number of the PSA PS API. It will be incremented in small updates that are unlikely to include breaking changes */ + + +/** + * \brief create a new or modify an existing key/value pair + * + * \param[in] uid the identifier for the data + * \param[in] data_length The size in bytes of the data in `p_data` + * \param[in] p_data A buffer containing the data + * \param[in] create_flags The flags indicating the properties of the data + * + * \return A status indicating the success/failure of the operation + + * \retval PSA_SUCCESS The operation completed successfully + * \retval PSA_ERROR_NOT_PERMITTED The operation failed because the provided uid value was already created with PSA_STORAGE_WRITE_ONCE_FLAG + * \retval PSA_ERROR_INVALID_ARGUMENT The operation failed because one or more of the given arguments were invalid. + * \retval PSA_ERROR_NOT_SUPPORTED The operation failed because one or more of the flags provided in `create_flags` is not supported or is not valid + * \retval PSA_ERROR_INSUFFICIENT_STORAGE The operation failed because there was insufficient space on the storage medium + * \retval PSA_ERROR_STORAGE_FAILURE The operation failed because the physical storage has failed (Fatal error) + * \retval PSA_ERROR_GENERIC_ERROR The operation failed because of an unspecified internal failure + */ +psa_status_t psa_ps_set(psa_storage_uid_t uid, + size_t data_length, + const void *p_data, + psa_storage_create_flags_t create_flags); + +/** + * \brief Retrieve the value for a provided uid + * + * \param[in] uid The identifier for the data + * \param[in] data_offset The offset within the data associated with the `uid` to start retrieving data + * \param[in] data_length The amount of data to read (and the minimum allocated size of the `p_data` buffer) + * \param[out] p_data The buffer where the data will be placed upon successful completion + * \param[out] p_data_length The actual amount of data returned + * + * \return A status indicating the success/failure of the operation + * + * \retval PSA_SUCCESS The operation completed successfully + * \retval PSA_ERROR_INVALID_ARGUMENT The operation failed because one or more of the given arguments were invalid (null pointer, wrong flags etc.) + * \retval PSA_ERROR_DOES_NOT_EXIST The operation failed because the provided uid value was not found in the storage + * \retval PSA_ERROR_BUFFER_TOO_SMALL The operation failed because the data associated with provided uid does not fit `data_size` + * \retval PSA_ERROR_STORAGE_FAILURE The operation failed because the physical storage has failed (Fatal error) + * \retval PSA_ERROR_GENERIC_ERROR The operation failed because of an unspecified internal failure + * \retval PSA_ERROR_DATA_CORRUPT The operation failed because of an authentication failure when attempting to get the key + * \retval PSA_ERROR_INVALID_SIGNATURE The operation failed because the data associated with the UID failed authentication + */ +psa_status_t psa_ps_get(psa_storage_uid_t uid, + size_t data_offset, + size_t data_length, + void *p_data, + size_t *p_data_length); + +/** + * \brief Retrieve the metadata about the provided uid + * + * \param[in] uid The identifier for the data + * \param[out] p_info A pointer to the `psa_storage_info_t` struct that will be populated with the metadata + * + * \return A status indicating the success/failure of the operation + * + * \retval PSA_SUCCESS The operation completed successfully + * \retval PSA_ERROR_INVALID_ARGUMENT The operation failed because one or more of the given arguments were invalid (null pointer, wrong flags etc.) + * \retval PSA_ERROR_DOES_NOT_EXIST The operation failed because the provided uid value was not found in the storage + * \retval PSA_ERROR_STORAGE_FAILURE The operation failed because the physical storage has failed (Fatal error) + * \retval PSA_ERROR_GENERIC_ERROR The operation failed because of an unspecified internal failure + * \retval PSA_ERROR_DATA_CORRUPT The operation failed because of an authentication failure when attempting to get the key + * \retval PSA_ERROR_INVALID_SIGNATURE The operation failed because the data associated with the UID failed authentication + */ +psa_status_t psa_ps_get_info(psa_storage_uid_t uid, struct psa_storage_info_t *p_info); + +/** + * \brief Remove the provided uid and its associated data from the storage + * + * \param[in] uid The identifier for the data to be removed + * + * \return A status indicating the success/failure of the operation + * + * \retval PSA_SUCCESS The operation completed successfully + * \retval PSA_ERROR_INVALID_ARGUMENT The operation failed because one or more of the given arguments were invalid (null pointer, wrong flags etc.) + * \retval PSA_ERROR_DOES_NOT_EXIST The operation failed because the provided uid value was not found in the storage + * \retval PSA_ERROR_NOT_PERMITTED The operation failed because the provided uid value was created with psa_eps_WRITE_ONCE_FLAG + * \retval PSA_ERROR_STORAGE_FAILURE The operation failed because the physical storage has failed (Fatal error) + * \retval PSA_ERROR_GENERIC_ERROR The operation failed because of an unspecified internal failure + */ +psa_status_t psa_ps_remove(psa_storage_uid_t uid); + +/** + * Creates an asset based on the given identifier, the maximum size and + * creation flags. This create allocates the space in the secure storage + * area without setting any data in the asset. + * + * It is only necessary to call this function for items that will be written + * with the \ref psa_ps_set_extended function. If only the \ref psa_ps_set function + * is needed, calls to this function are redundant. + * + * If the \ref PSA_STORAGE_FLAG_WRITE_ONCE flag is passed, implementations should + * return \ref PSA_ERROR_NOT_SUPPORTED. + * + * This function is optional. Not all PSA Protected Storage Implementations + * will implement this function. Consult the documentation of your chosen + * platform to determine if it is present. + * + * \param[in] uid A unique identifier for the asset. + * \param[in] size The maximum size in bytes of the asset. + * \param[in] create_flags Create flags \ref psa_storage_create_flags_t. + * + * \retval PSA_SUCCESS The assest does not exist and the input parameters are correct or + * the asset already exists, the input parameters are the same that + * have been used to create the asset and the owner is the same and the current asset content is kept + * TDB: "Owner is the same" doesn't really make sense from a PSA perspective, as each partition + * has its own UID space, making other partitions' data unadressable + * \retval PSA_ERROR_STORAGE_FAILURE The create action has a physical storage error + * \retval PSA_ERROR_INSUFFICIENT_STORAGE The maximum size is bigger of the current available space + * \retval PSA_ERROR_NOT_SUPPORTED One or more create_flags are not valid or supported + * \retval PSA_ERROR_INVALID_ARGUMENT The asset exists and the input paramters are not the same as the existing asset + * \retval PSA_ERROR_NOT_SUPPORTED The implementation of the API does not support this function + * \retval PSA_ERROR_GENERIC_ERROR The operation has failed due to an unspecified error + */ +psa_status_t psa_ps_create(psa_storage_uid_t uid, + size_t size, + psa_storage_create_flags_t create_flags); + +/** + * Sets partial data into an asset based on the given identifier, data_offset, + * data length and p_data. + * + * Before calling this function, the asset must have been created with a call + * to \ref psa_ps_create. + * + * This function is optional. Not all PSA Protected Storage Implementations + * will implement this function. Consult the documentation of your chosen + * platform to determine if it is present. + * + * \param[in] uid The unique identifier for the asset. + * \param[in] data_offset Offset within the asset to start the write. + * \param[in] data_length The size in bytes of the data in p_data to write. + * \param[in] p_data Pointer to a buffer which contains the data to write. + * + * \retval PSA_SUCCESS If the asset exists, the input parameters are correct and the data + * is correctly written in the physical storage + * \retval PSA_ERROR_STORAGE_FAILURE If the data is not written correctly in the physical storage + * \retval PSA_ERROR_INVALID_ARGUMENT The operation failed because one or more of the given arguments were invalid (null pointer, wrong flags, etc) + * \retval PSA_ERROR_DOES_NOT_EXIST The specified UID was not found + * \retval PSA_ERROR_NOT_SUPPORTED The implementation of the API does not support this function + * \retval PSA_ERROR_GENERIC_ERROR The operation failed due to an unspecified error + * \retval PSA_ERROR_DATA_CORRUPT The operation failed because the existing data has been corrupted + * \retval PSA_ERROR_INVALID_SIGNATURE The operation failed because the existing data failed authentication (MAC check failed) + */ +psa_status_t psa_ps_set_extended(psa_storage_uid_t uid, + size_t data_offset, + size_t data_length, + const void *p_data); + +/** + * Returns a bitmask with flags set for all of the optional features supported + * by the implementation. + * + * Currently defined flags are limited to: + * - \ref PSA_STORAGE_SUPPORT_SET_EXTENDED + */ +uint32_t psa_ps_get_support(void); + +#ifdef __cplusplus +} +#endif + + +#endif // __PSA_PROTECTED_STORAGE_H__ diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/inc/psa/service.h b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/inc/psa/service.h new file mode 100644 index 0000000..355c966 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/inc/psa/service.h @@ -0,0 +1,28 @@ +/* Copyright (c) 2017-2018 ARM Limited + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#if defined(TARGET_TFM) + +#include "interface/include/psa_service.h" +#include "secure_fw/core/ipc/include/tfm_utils.h" +#define SPM_PANIC(format, ...) tfm_panic() + +#else + +#error "Compiling psa service header on non-secure target is not allowed" + +#endif diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/inc/psa/storage_common.h b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/inc/psa/storage_common.h new file mode 100644 index 0000000..1747f14 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/inc/psa/storage_common.h @@ -0,0 +1,64 @@ +/* Copyright (C) 2019, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** @file +@brief This file includes common definitions for PSA storage +*/ + +#ifndef __PSA_STORAGE_COMMON_H__ +#define __PSA_STORAGE_COMMON_H__ + +#include +#include +#include "psa/error.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** \brief Flags used when creating a data entry + */ +typedef uint32_t psa_storage_create_flags_t; + +#define PSA_STORAGE_FLAG_NONE 0 /**< No flags to pass */ +#define PSA_STORAGE_FLAG_WRITE_ONCE (1 << 0) /**< The data associated with the uid will not be able to be modified or deleted. Intended to be used to set bits in `psa_storage_create_flags_t`*/ +#define PSA_STORAGE_FLAG_NO_CONFIDENTIALITY (1 << 1) /**< The data associated with the uid is public and therefore does not require confidentiality. It therefore only needs to be integrity protected */ +#define PSA_STORAGE_FLAG_NO_REPLAY_PROTECTION (1 << 2) /**< The data associated with the uid does not require replay protection. This may permit faster storage - but it permits an attecker with physical access to revert to an earlier version of the data. */ + +/** \brief A type for UIDs used for identifying data + */ +typedef uint64_t psa_storage_uid_t; + +/** + * \brief A container for metadata associated with a specific uid + */ +struct psa_storage_info_t { + size_t capacity; /**< The allocated capacity of the storage associated with a UID **/ + size_t size; /**< The size of the data associated with a uid **/ + psa_storage_create_flags_t flags; /**< The flags set when the uid was created **/ +}; + +/** \brief Flag indicating that \ref psa_storage_create and \ref psa_storage_set_extended are supported */ +#define PSA_STORAGE_SUPPORT_SET_EXTENDED (1 << 0) + +/** \brief PSA storage specific error codes */ +#define PSA_ERROR_DATA_CORRUPT ((psa_status_t)-152) + +#ifdef __cplusplus +} +#endif + +#endif // __PSA_STORAGE_COMMON_H__ diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/inc/psa_manifest/sid.h b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/inc/psa_manifest/sid.h new file mode 100644 index 0000000..42fe92b --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/inc/psa_manifest/sid.h @@ -0,0 +1,23 @@ +/* Copyright (c) 2017-2018 ARM Limited + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __SID_H__ +#define __SID_H__ + +#include "autogen_sid.h" + +#endif // __SID_H__ diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/COMPONENT_PSA_SRV_IMPL/mbed_lib.json b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/COMPONENT_PSA_SRV_IMPL/mbed_lib.json new file mode 100644 index 0000000..ac6c485 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/COMPONENT_PSA_SRV_IMPL/mbed_lib.json @@ -0,0 +1,12 @@ +{ + "name": "psa-services", + "requires": [ + "drivers", + "platform", + "mbedtls", + "storage", + "flashiap-block-device", + "tdbstore", + "storage_tdb_internal" + ] +} diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_EMUL/psa_attest_inject_key.c b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_EMUL/psa_attest_inject_key.c new file mode 100755 index 0000000..acb93a6 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_EMUL/psa_attest_inject_key.c @@ -0,0 +1,38 @@ +/* +* Copyright (c) 2018-2019 ARM Limited. All rights reserved. +* +* SPDX-License-Identifier: Apache-2.0 +* +* Licensed under the Apache License, Version 2.0 (the License); you may +* not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an AS IS BASIS, WITHOUT +* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include "psa_attest_inject_key.h" +#include "psa_inject_attestation_key_impl.h" + +psa_status_t +psa_attestation_inject_key(const uint8_t *key_data, + size_t key_data_length, + psa_key_type_t type, + uint8_t *public_key_data, + size_t public_key_data_size, + size_t *public_key_data_length) +{ + psa_status_t status = PSA_SUCCESS; + status = psa_attestation_inject_key_impl(key_data, + key_data_length, + type, + public_key_data, + public_key_data_size, + public_key_data_length); + return (status); +} diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_EMUL/psa_initial_attestation_api.c b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_EMUL/psa_initial_attestation_api.c new file mode 100755 index 0000000..c4eb017 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_EMUL/psa_initial_attestation_api.c @@ -0,0 +1,70 @@ +/* +* Copyright (c) 2018-2019 ARM Limited. All rights reserved. +* +* SPDX-License-Identifier: Apache-2.0 +* +* Licensed under the Apache License, Version 2.0 (the License); you may +* not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an AS IS BASIS, WITHOUT +* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include "psa_initial_attestation_api.h" +#include "psa/client.h" +#include "attestation.h" +#include + +int32_t g_caller_id = 0; + +enum psa_attest_err_t +psa_initial_attest_get_token(const uint8_t *challenge_obj, + uint32_t challenge_size, + uint8_t *token, + uint32_t *token_size) { + enum psa_attest_err_t err; + + err = attest_init(); + if (err != PSA_ATTEST_ERR_SUCCESS) + { + return err; + } + + psa_invec in_vec[1] = { { challenge_obj, challenge_size } }; + psa_outvec out_vec[1] = { { token, *token_size } }; + + err = initial_attest_get_token(in_vec, 1, out_vec, 1); + if (err != PSA_ATTEST_ERR_SUCCESS) + { + return err; + } + + *token_size = out_vec[0].len; + + return err; +} + +enum psa_attest_err_t +psa_initial_attest_get_token_size(uint32_t challenge_size, + uint32_t *token_size) { + enum psa_attest_err_t err; + + err = attest_init(); + if (err != PSA_ATTEST_ERR_SUCCESS) + { + return err; + } + + psa_invec in_vec[1] = { { &challenge_size, sizeof(challenge_size) } }; + psa_outvec out_vec[1] = { { token_size, sizeof(*token_size) } }; + + err = initial_attest_get_token_size(in_vec, 1, out_vec, 1); + + return err; +} diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IMPL/attest_boot_status_loader.c b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IMPL/attest_boot_status_loader.c new file mode 100755 index 0000000..8413a67 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IMPL/attest_boot_status_loader.c @@ -0,0 +1,95 @@ +/* +* Copyright (c) 2018-2019 ARM Limited. All rights reserved. +* +* SPDX-License-Identifier: Apache-2.0 +* +* Licensed under the Apache License, Version 2.0 (the License); you may +* not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an AS IS BASIS, WITHOUT +* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include +#include +#include "attestation.h" +#include "attestation_bootloader_data.h" +#include "tfm_impl/tfm_boot_status.h" +#ifdef TARGET_TFM +#include "region_defs.h" +#endif + +/*! + * \def SHARED_DATA_INITIALZED and SHARED_DATA_UNNITIALZED + * + * \brief Indicates that shared data was already initialized. + */ +#define SHARED_DATA_UNNITIALZED (0u) +#define SHARED_DATA_INITIALZED (1u) + +/*! + * \var shared_data_init_done + * + * \brief Indicates whether shared data area was already initialized. + * + */ +static uint32_t shared_data_init_done = SHARED_DATA_UNNITIALZED; + +enum psa_attest_err_t +attest_get_boot_data(uint8_t major_type, void *ptr, uint32_t len) { + if (shared_data_init_done == SHARED_DATA_INITIALZED) + { + return PSA_ATTEST_ERR_SUCCESS; + } + struct shared_data_tlv_header *tlv_header; + struct shared_data_tlv_header *ptr_tlv_header; + struct shared_data_tlv_entry *tlv_entry; + uintptr_t tlv_end, offset; + + /* Get the boundaries of TLV section */ + tlv_header = (struct shared_data_tlv_header *)BOOT_TFM_SHARED_DATA_BASE; + if (tlv_header->tlv_magic != SHARED_DATA_TLV_INFO_MAGIC) + { + return PSA_ATTEST_ERR_INIT_FAILED; + } + tlv_end = (uintptr_t)BOOT_TFM_SHARED_DATA_BASE + (uintptr_t)tlv_header->tlv_tot_len; + offset = (uintptr_t)BOOT_TFM_SHARED_DATA_BASE + (uintptr_t)SHARED_DATA_HEADER_SIZE; + + /* Add header to output buffer as well */ + if (len < SHARED_DATA_HEADER_SIZE) + { + return PSA_ATTEST_ERR_INIT_FAILED; + } + ptr_tlv_header = (struct shared_data_tlv_header *)ptr; + ptr_tlv_header->tlv_magic = SHARED_DATA_TLV_INFO_MAGIC; + ptr_tlv_header->tlv_tot_len = SHARED_DATA_HEADER_SIZE; + + ptr = (uint8_t *)ptr + SHARED_DATA_HEADER_SIZE; + /* Iterates over the TLV section and copy TLVs with requested major + * type to the provided buffer. + */ + for (; offset < tlv_end; offset += tlv_entry->tlv_len) + { + tlv_entry = (struct shared_data_tlv_entry *)offset; + if (GET_MAJOR(tlv_entry->tlv_type) == major_type) { + if (len < ptr_tlv_header->tlv_tot_len + tlv_entry->tlv_len) { + return PSA_ATTEST_ERR_INIT_FAILED; + } + memcpy(ptr, (const void *)tlv_entry, tlv_entry->tlv_len); + ptr = (uint8_t *)ptr + tlv_entry->tlv_len; + ptr_tlv_header->tlv_tot_len += tlv_entry->tlv_len; + } + if (tlv_entry->tlv_len == 0) { + break; + } + } + + shared_data_init_done = SHARED_DATA_INITIALZED; + return PSA_ATTEST_ERR_SUCCESS; +} diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IMPL/attest_crypto.c b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IMPL/attest_crypto.c new file mode 100755 index 0000000..f92fc18 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IMPL/attest_crypto.c @@ -0,0 +1,275 @@ +/* + * attest_crypto.c + * + * Copyright (c) 2018-2019, Laurence Lundblade. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + * See BSD-3-Clause license in README.md + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "t_cose_crypto.h" +#include "tfm_plat_defs.h" +#include "psa/crypto.h" +#include "tfm_plat_crypto_keys.h" +#include + +#define PSA_ATTESTATION_PRIVATE_KEY_ID 17 + +/** + * \brief Context for PSA hash adaptation. + * + * Hash context for PSA hash implementation. This is fit into and cast + * to/from struct \ref t_cose_crypto_hash. + */ +struct t_cose_psa_crypto_hash { + psa_status_t status; + psa_hash_operation_t operation; +}; + +enum t_cose_err_t +t_cose_crypto_pub_key_sign(int32_t cose_alg_id, + int32_t key_select, + struct useful_buf_c hash_to_sign, + struct useful_buf signature_buffer, + struct useful_buf_c *signature) { + enum t_cose_err_t cose_ret = T_COSE_SUCCESS; + psa_status_t crypto_ret; + const size_t sig_size = t_cose_signature_size(cose_alg_id); + + (void)key_select; + + psa_key_handle_t handle; + + if (sig_size > signature_buffer.len) + { + return T_COSE_ERR_SIG_BUFFER_SIZE; + } + + crypto_ret = psa_open_key(PSA_ATTESTATION_PRIVATE_KEY_ID, &handle); + if (crypto_ret != PSA_SUCCESS) + { + return T_COSE_ERR_NO_KID; + } + + crypto_ret = psa_sign_hash(handle, + PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_256), + hash_to_sign.ptr, + hash_to_sign.len, + signature_buffer.ptr, + signature_buffer.len, + &(signature->len)); + + + if (crypto_ret != PSA_SUCCESS) + { + psa_close_key(handle); + cose_ret = T_COSE_ERR_UNSUPPORTED_SIGNING_ALG; + } else + { + signature->ptr = signature_buffer.ptr; + } + + psa_close_key(handle); + return cose_ret; +} + +enum t_cose_err_t +t_cose_crypto_get_ec_pub_key(int32_t key_select, + struct useful_buf_c kid, + int32_t *cose_curve_id, + struct useful_buf buf_to_hold_x_coord, + struct useful_buf buf_to_hold_y_coord, + struct useful_buf_c *x_coord, + struct useful_buf_c *y_coord) { + + enum tfm_plat_err_t err; + enum ecc_curve_t cose_curve; + struct ecc_key_t attest_key = {0}; + uint8_t key_buf[ECC_P_256_KEY_SIZE] = {0}; + + (void)key_select; + + /* Get the initial attestation key */ + err = tfm_plat_get_initial_attest_key(key_buf, sizeof(key_buf), + &attest_key, &cose_curve); + + /* Check the availability of the private key */ + if (err != TFM_PLAT_ERR_SUCCESS || + attest_key.pubx_key == NULL || + attest_key.puby_key == NULL) + { + return T_COSE_ERR_KEY_BUFFER_SIZE; + } + + *cose_curve_id = (int32_t)cose_curve; + + /* Check buffer size to avoid overflow */ + if (buf_to_hold_x_coord.len < attest_key.pubx_key_size) + { + return T_COSE_ERR_KEY_BUFFER_SIZE; + } + + /* Copy the X coordinate of the public key to the buffer */ + memcpy(buf_to_hold_x_coord.ptr, + (const void *)attest_key.pubx_key, + attest_key.pubx_key_size); + + /* Update size */ + buf_to_hold_x_coord.len = attest_key.pubx_key_size; + + /* Check buffer size to avoid overflow */ + if (buf_to_hold_y_coord.len < attest_key.puby_key_size) + { + return T_COSE_ERR_KEY_BUFFER_SIZE; + } + + /* Copy the Y coordinate of the public key to the buffer */ + memcpy(buf_to_hold_y_coord.ptr, + (const void *)attest_key.puby_key, + attest_key.puby_key_size); + + /* Update size */ + buf_to_hold_y_coord.len = attest_key.puby_key_size; + + x_coord->ptr = buf_to_hold_x_coord.ptr; + x_coord->len = buf_to_hold_x_coord.len; + y_coord->ptr = buf_to_hold_y_coord.ptr; + y_coord->len = buf_to_hold_y_coord.len; + + return T_COSE_SUCCESS; +} + +/** + * \brief Check some of the sizes for hash implementation. + * + * \return Value from \ref t_cose_err_t error if sizes are not correct. + * + * It makes sure the constants in the header file match the local + * implementation. This gets evaluated at compile time and will + * optimize out to nothing when all checks pass. + */ +static inline enum t_cose_err_t check_hash_sizes() +{ + if (T_COSE_CRYPTO_SHA256_SIZE != PSA_HASH_SIZE(PSA_ALG_SHA_256)) { + return T_COSE_ERR_HASH_GENERAL_FAIL; + } + + return T_COSE_SUCCESS; +} + +/** + * \brief Convert COSE algorithm ID to a PSA algorithm ID + * + * \param[in] cose_hash_alg_id The COSE-based ID for the + * + * \return PSA-based hash algorithm ID, or MD4 in the case of error. + * + */ +static inline psa_algorithm_t cose_hash_alg_id_to_psa(int32_t cose_hash_alg_id) +{ + psa_algorithm_t return_value; + + switch (cose_hash_alg_id) { + case COSE_ALG_SHA256_PROPRIETARY: + return_value = PSA_ALG_SHA_256; + break; + default: + return_value = PSA_ALG_MD4; + break; + } + + return return_value; +} + +enum t_cose_err_t +t_cose_crypto_hash_start(struct t_cose_crypto_hash *hash_ctx, + int32_t cose_hash_alg_id) { + enum t_cose_err_t cose_ret = T_COSE_SUCCESS; + psa_status_t psa_ret; + struct t_cose_psa_crypto_hash *psa_hash_ctx; + + /* These next 3 lines optimize to nothing except when there is + * failure. + */ + cose_ret = check_hash_sizes(); + if (cose_ret != T_COSE_SUCCESS) + { + return cose_ret; + } + + psa_hash_ctx = (struct t_cose_psa_crypto_hash *)hash_ctx; + memset(&psa_hash_ctx->operation, 0, sizeof(psa_hash_operation_t)); + + psa_ret = psa_hash_setup(&psa_hash_ctx->operation, + cose_hash_alg_id_to_psa(cose_hash_alg_id)); + + if (psa_ret == PSA_SUCCESS) + { + psa_hash_ctx->status = PSA_SUCCESS; + cose_ret = T_COSE_SUCCESS; + } else if (psa_ret == PSA_ERROR_NOT_SUPPORTED) + { + cose_ret = T_COSE_ERR_UNSUPPORTED_HASH; + } else + { + cose_ret = T_COSE_ERR_HASH_GENERAL_FAIL; + } + + return cose_ret; +} + +void t_cose_crypto_hash_update(struct t_cose_crypto_hash *hash_ctx, + struct useful_buf_c data_to_hash) +{ + struct t_cose_psa_crypto_hash *psa_hash_ctx; + + psa_hash_ctx = (struct t_cose_psa_crypto_hash *)hash_ctx; + + if (psa_hash_ctx->status == PSA_SUCCESS) { + if (data_to_hash.ptr != NULL) { + psa_hash_ctx->status = psa_hash_update(&psa_hash_ctx->operation, + data_to_hash.ptr, + data_to_hash.len); + } + } +} + +enum t_cose_err_t +t_cose_crypto_hash_finish(struct t_cose_crypto_hash *hash_ctx, + struct useful_buf buffer_to_hold_result, + struct useful_buf_c *hash_result) { + enum t_cose_err_t cose_ret = T_COSE_SUCCESS; + psa_status_t psa_ret; + struct t_cose_psa_crypto_hash *psa_hash_ctx; + + psa_hash_ctx = (struct t_cose_psa_crypto_hash *)hash_ctx; + + if (psa_hash_ctx->status == PSA_SUCCESS) + { + psa_ret = psa_hash_finish(&psa_hash_ctx->operation, + buffer_to_hold_result.ptr, + buffer_to_hold_result.len, + &(hash_result->len)); + + if (psa_ret == PSA_SUCCESS) { + hash_result->ptr = buffer_to_hold_result.ptr; + cose_ret = T_COSE_SUCCESS; + } else if (psa_ret == PSA_ERROR_BUFFER_TOO_SMALL) { + cose_ret = T_COSE_ERR_HASH_BUFFER_SIZE; + } else { + cose_ret = T_COSE_ERR_HASH_GENERAL_FAIL; + } + } else + { + cose_ret = T_COSE_ERR_HASH_GENERAL_FAIL; + } + + return cose_ret; +} diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IMPL/attest_crypto_keys.c b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IMPL/attest_crypto_keys.c new file mode 100755 index 0000000..e67227c --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IMPL/attest_crypto_keys.c @@ -0,0 +1,182 @@ +/* +* Copyright (c) 2018-2019 ARM Limited. All rights reserved. +* +* SPDX-License-Identifier: Apache-2.0 +* +* Licensed under the Apache License, Version 2.0 (the License); you may +* not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an AS IS BASIS, WITHOUT +* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include "tfm_plat_crypto_keys.h" +#include "psa/crypto.h" + +#include +#include + + +#define ONE_BYTE (1u) +#define PSA_ATTESTATION_PRIVATE_KEY_ID 17 + +/** + * \brief Copy the key to the destination buffer + * + * \param[out] p_dst Pointer to buffer where to store the key + * \param[in] p_src Pointer to the key + * \param[in] size Length of the key + */ +static inline void copy_key(uint8_t *p_dst, const uint8_t *p_src, size_t size) +{ + uint32_t i; + + for (i = size; i > 0; i--) { + *p_dst = *p_src; + p_src++; + p_dst++; + } +} + +static psa_status_t get_curve(psa_key_type_t type, enum ecc_curve_t *curve_type) +{ + psa_ecc_curve_t curve = PSA_KEY_TYPE_GET_CURVE(type); + switch (curve) { + case PSA_ECC_CURVE_SECP_R1: + *curve_type = P_256; + break; + case PSA_ECC_CURVE_MONTGOMERY: + *curve_type = X25519; + break; + default: + return (PSA_ERROR_NOT_SUPPORTED); + } + + return PSA_SUCCESS; +} + +enum tfm_plat_err_t +tfm_plat_get_initial_attest_key(uint8_t *key_buf, + uint32_t size, + struct ecc_key_t *ecc_key, + enum ecc_curve_t *curve_type) + +{ + uint8_t *key_dst = NULL; + uint8_t *key_src; + uint32_t key_size; + + psa_status_t crypto_ret; + + uint8_t *public_key = NULL; + psa_key_type_t type; + psa_key_type_t public_type; + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + size_t bits; + size_t public_key_size = 0; + size_t public_key_length = 0; + + uint32_t initial_attestation_public_x_key_size = 0; + uint32_t initial_attestation_public_y_key_size = 0; + + psa_key_handle_t handle; + + crypto_ret = psa_open_key(PSA_ATTESTATION_PRIVATE_KEY_ID, &handle); + if (crypto_ret != PSA_SUCCESS) + { + return TFM_PLAT_ERR_SYSTEM_ERR; + } + + crypto_ret = psa_get_key_attributes(handle, &attributes); + if (crypto_ret != PSA_SUCCESS) + { + psa_close_key(handle); + return TFM_PLAT_ERR_SYSTEM_ERR; + } + type = psa_get_key_type(&attributes); + if (!PSA_KEY_TYPE_IS_ECC(type)) + { + psa_close_key(handle); + return TFM_PLAT_ERR_SYSTEM_ERR; + } + public_type = PSA_KEY_TYPE_PUBLIC_KEY_OF_KEY_PAIR(type); + bits = psa_get_key_bits(&attributes); + public_key_size = PSA_KEY_EXPORT_MAX_SIZE(public_type, bits); + public_key = (uint8_t *) malloc(public_key_size); + if (public_key == NULL) + { + psa_close_key(handle); + return TFM_PLAT_ERR_SYSTEM_ERR; + } + + crypto_ret = psa_export_public_key(handle, + public_key, public_key_size, + &public_key_length); + if (crypto_ret != PSA_SUCCESS) + { + free(public_key); + psa_close_key(handle); + return TFM_PLAT_ERR_SYSTEM_ERR; + } + + /* Set the EC curve type which the key belongs to */ + crypto_ret = get_curve(type, curve_type); + if (crypto_ret != PSA_SUCCESS) + { + free(public_key); + psa_close_key(handle); + return TFM_PLAT_ERR_SYSTEM_ERR; + } + + key_src = public_key; + key_dst = key_buf; + + /* The representation of an ECC public key is: + ** -The byte 0x04 + ** - `x_P` as a `ceiling(m/8)`-byte string, big-endian + ** - `y_P` as a `ceiling(m/8)`-byte string, big-endian + ** - where m is the bit size associated with the curve + ** - 1 byte + 2 * point size + */ + initial_attestation_public_x_key_size = ceil((public_key_length - 1) / 2); + initial_attestation_public_y_key_size = ceil((public_key_length - 1) / 2); + + /* Copy the x-coordinate of public key to the buffer */ + if (initial_attestation_public_x_key_size != 0) + { + key_src = key_src + ONE_BYTE; + key_size = initial_attestation_public_x_key_size; + copy_key(key_dst, key_src, key_size); + ecc_key->pubx_key = key_dst; + ecc_key->pubx_key_size = key_size; + key_dst = key_dst + key_size; + } else + { + ecc_key->pubx_key = NULL; + ecc_key->pubx_key_size = 0; + } + + /* Copy the y-coordinate of public key to the buffer */ + if (initial_attestation_public_y_key_size != 0) + { + key_src += initial_attestation_public_x_key_size; + key_size = initial_attestation_public_y_key_size; + copy_key(key_dst, key_src, key_size); + ecc_key->puby_key = key_dst; + ecc_key->puby_key_size = key_size; + } else + { + ecc_key->puby_key = NULL; + ecc_key->puby_key_size = 0; + } + + free(public_key); + psa_close_key(handle); + return TFM_PLAT_ERR_SUCCESS; +} diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IMPL/attest_iat_claims_loader.c b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IMPL/attest_iat_claims_loader.c new file mode 100755 index 0000000..8cae245 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IMPL/attest_iat_claims_loader.c @@ -0,0 +1,222 @@ +/* +* Copyright (c) 2018-2019 ARM Limited. All rights reserved. +* +* SPDX-License-Identifier: Apache-2.0 +* +* Licensed under the Apache License, Version 2.0 (the License); you may +* not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an AS IS BASIS, WITHOUT +* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include +#include +#include +#include +#include "tfm_plat_boot_seed.h" +#include "attestation_bootloader_data.h" +#include "tfm_attest_hal.h" +#include "psa_initial_attestation_api.h" +#include "attestation.h" +#include "psa/crypto.h" +#include "psa/lifecycle.h" + +extern int32_t g_caller_id; + +#define ATTEST_PUB_KEY_SHA_256_SIZE (32u) +#define PSA_ATTESTATION_PRIVATE_KEY_ID 17 + +static enum tfm_security_lifecycle_t security_lifecycle_psa_to_tfm(void) +{ + uint32_t lc = psa_security_lifecycle_state(); + switch (lc) { + case PSA_LIFECYCLE_UNKNOWN: + return TFM_SLC_UNKNOWN; + case PSA_LIFECYCLE_ASSEMBLY_AND_TEST: + return TFM_SLC_ASSEMBLY_AND_TEST; + case PSA_LIFECYCLE_PSA_ROT_PROVISIONING: + return TFM_SLC_PSA_ROT_PROVISIONING; + case PSA_LIFECYCLE_SECURED: + return TFM_SLC_SECURED; + case PSA_LIFECYCLE_NON_PSA_ROT_DEBUG: + return TFM_SLC_NON_PSA_ROT_DEBUG; + case PSA_LIFECYCLE_RECOVERABLE_PSA_ROT_DEBUG: + return TFM_SLC_RECOVERABLE_PSA_ROT_DEBUG; + case PSA_LIFECYCLE_DECOMMISSIONED: + return TFM_SLC_DECOMMISSIONED; + default: + return TFM_SLC_UNKNOWN; + } +} + +/* Hash of attestation public key */ +static enum tfm_plat_err_t attest_public_key_sha256(uint32_t *size, uint8_t *buf) +{ + psa_key_handle_t handle = 0; + + uint8_t *public_key = NULL; + psa_key_type_t type; + psa_key_type_t public_type; + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + size_t bits; + size_t public_key_size = 0; + size_t public_key_length = 0; + + psa_status_t crypto_ret; + enum tfm_plat_err_t status = TFM_PLAT_ERR_SUCCESS; + psa_hash_operation_t hash_handle = {0}; + + crypto_ret = psa_open_key(PSA_ATTESTATION_PRIVATE_KEY_ID, &handle); + if (crypto_ret != PSA_SUCCESS) { + return TFM_PLAT_ERR_SYSTEM_ERR; + } + + crypto_ret = psa_get_key_attributes(handle, &attributes); + if (crypto_ret != PSA_SUCCESS) { + status = TFM_PLAT_ERR_SYSTEM_ERR; + goto exit; + } + type = psa_get_key_type(&attributes); + if (!PSA_KEY_TYPE_IS_ECC(type)) { + status = TFM_PLAT_ERR_SYSTEM_ERR; + goto exit; + } + public_type = PSA_KEY_TYPE_PUBLIC_KEY_OF_KEY_PAIR(type); + bits = psa_get_key_bits(&attributes); + public_key_size = PSA_KEY_EXPORT_MAX_SIZE(public_type, bits); + public_key = (uint8_t *) malloc(public_key_size); + if (public_key == NULL) { + status = TFM_PLAT_ERR_SYSTEM_ERR; + goto exit; + } + + crypto_ret = psa_export_public_key(handle, + public_key, public_key_size, + &public_key_length); + if (crypto_ret != PSA_SUCCESS) { + status = TFM_PLAT_ERR_SYSTEM_ERR; + goto exit; + } + + crypto_ret = psa_hash_setup(&hash_handle, PSA_ALG_SHA_256); + if (crypto_ret != PSA_SUCCESS) { + status = TFM_PLAT_ERR_SYSTEM_ERR; + goto exit; + } + + psa_hash_update(&hash_handle, public_key, public_key_length); + + crypto_ret = psa_hash_finish(&hash_handle, + buf, + ATTEST_PUB_KEY_SHA_256_SIZE, + (size_t *) size); + if (crypto_ret != PSA_SUCCESS) { + status = TFM_PLAT_ERR_SYSTEM_ERR; + goto exit; + } + +exit: + if (public_key != NULL) { + free(public_key); + } + psa_close_key(handle); + return status; +} + +/** + * \brief Copy the device specific ID to the destination buffer + * + * \param[out] p_dst Pointer to buffer where to store ID + * \param[in] p_src Pointer to the ID + * \param[in] size Length of the ID + */ +static inline void copy_id(uint8_t *p_dst, uint8_t *p_src, size_t size) +{ + uint32_t i; + + for (i = size; i > 0; i--) { + *p_dst = *p_src; + p_src++; + p_dst++; + } +} + +enum psa_attest_err_t attest_get_caller_client_id(int32_t *caller_id) +{ + *caller_id = g_caller_id; + return PSA_ATTEST_ERR_SUCCESS; +} + +/* Boot seed data is part of bootloader status*/ +enum tfm_plat_err_t tfm_plat_get_boot_seed(uint32_t size, uint8_t *buf) +{ + return (enum tfm_plat_err_t)PSA_ATTEST_ERR_CLAIM_UNAVAILABLE; +} + +/** + * Instance ID is mapped to EAT Universal Entity ID (UEID) + * This implementation creates the instance ID as follows: + * - byte 0: 0x01 indicates the type of UEID to be GUID + * - byte 1-32: Hash of attestation public key. Public key is hashed in raw + * format without any encoding. + */ +enum tfm_plat_err_t tfm_plat_get_instance_id(uint32_t *size, uint8_t *buf) +{ + enum tfm_plat_err_t status; + + buf[0] = 0x01; /* First byte is type byte: 0x01 indicates GUID */ + + status = attest_public_key_sha256(size, &buf[1]); + + /* Instance ID size: 1 type byte + size of public key hash */ + *size = *size + 1; + + return status; +} + +/* HW version data is part of bootloader status*/ +enum tfm_plat_err_t tfm_plat_get_hw_version(uint32_t *size, uint8_t *buf) +{ + return (enum tfm_plat_err_t)PSA_ATTEST_ERR_CLAIM_UNAVAILABLE; +} + +enum tfm_plat_err_t tfm_plat_get_implementation_id(uint32_t *size, uint8_t *buf) +{ + memcpy(buf, impl_id_data, *size); + return (enum tfm_plat_err_t)PSA_ATTEST_ERR_SUCCESS; +} + +/* Temporary Implementation of security lifecycle data: mandatory claim. +** tfm_attest_hal_get_security_lifecycle function should return +** 'PSA_ATTEST_ERR_CLAIM_UNAVAILABLE' if been called. +** Security lifecycle data is part of bootloader status data. +** Temp implementation of using psa_security_lifecycle_state */ + +enum tfm_security_lifecycle_t tfm_attest_hal_get_security_lifecycle(void) +{ + return security_lifecycle_psa_to_tfm(); +} + + +const char * +tfm_attest_hal_get_verification_service(uint32_t *size) +{ + *size = sizeof(verification_service_url) - 1; + return verification_service_url; +} + +const char * +tfm_attest_hal_get_profile_definition(uint32_t *size) +{ + *size = sizeof(attestation_profile_definition) - 1; + return attestation_profile_definition; +} + + diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IMPL/attestation_bootloader_data.c b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IMPL/attestation_bootloader_data.c new file mode 100755 index 0000000..797ecea --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IMPL/attestation_bootloader_data.c @@ -0,0 +1,64 @@ +/* +* Copyright (c) 2018-2019 ARM Limited. All rights reserved. +* +* SPDX-License-Identifier: Apache-2.0 +* +* Licensed under the Apache License, Version 2.0 (the License); you may +* not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an AS IS BASIS, WITHOUT +* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include "attestation_bootloader_data.h" + +/* Temporary Boodloader data - contains temp mandatory claims */ +__attribute__((aligned(4))) +const uint8_t temp_ram_page_data[] = { + 0x16, 0x20, 0xAC, 0x00, //shared_data_tlv_header + 0x83, 0x11, 0x0C, 0x00, // SW_TYPE + 0x4E, 0x53, 0x50, 0x45, 0x5F, 0x53, 0x50, 0x45, + 0x80, 0x11, 0x0A, 0x00, //SW_VERSION + 0x31, 0x2E, 0x31, 0x2E, 0x31, 0x31, + 0x82, 0x11, 0x06, 0x00, //SW_EPOCH + 0x00, 0x00, + 0x88, 0x11, 0x24, 0x00, //SW_MEASURE_VALUE + 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, + 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, + 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, + 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, + 0x81, 0x11, 0x24, 0x00, //SW_SIGNER_ID + 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, + 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, + 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, + 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, + 0x89, 0x11, 0x0A, 0x00, //SW_MEASURE_TYPE + 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, + 0x00, 0x10, 0x24, 0x00, //TLV_MINOR_IAS_BOOT_SEED + 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, + 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, + 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, + 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, + 0x01, 0x10, 0x16, 0x00, //TLV_MINOR_IAS_HW_VERSION + 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, + 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, + 0x31, 0x32 +}; + +/* Temporary Implementation ID data: mandatory claim represents the original +** implementation signer of the attestation key and identifies the contract +** between the report and verification */ +#define TEMP_IMPL_ID_DATA_SIZE (32u) + +#define TEMP_IMPL_ID_DATA 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, \ + 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, \ + 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, \ + 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF + +const uint8_t impl_id_data[TEMP_IMPL_ID_DATA_SIZE] = {TEMP_IMPL_ID_DATA}; diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IMPL/attestation_bootloader_data.h b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IMPL/attestation_bootloader_data.h new file mode 100755 index 0000000..6f0c560 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IMPL/attestation_bootloader_data.h @@ -0,0 +1,48 @@ +/* +* Copyright (c) 2018-2019 ARM Limited. All rights reserved. +* +* SPDX-License-Identifier: Apache-2.0 +* +* Licensed under the Apache License, Version 2.0 (the License); you may +* not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an AS IS BASIS, WITHOUT +* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#ifndef __ATTESTATION_BOOTLOADER_DATA_H__ +#define __ATTESTATION_BOOTLOADER_DATA_H__ + +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif + +/* Temp Shared data area between bootloader and runtime firmware */ +extern const uint8_t temp_ram_page_data[]; + +#define S_RAM_ALIAS_BASE (temp_ram_page_data) + +#define BOOT_TFM_SHARED_DATA_BASE S_RAM_ALIAS_BASE + +extern const uint8_t impl_id_data[]; + +/* Example verification service URL for initial attestation token - temporary data*/ +static const char verification_service_url[] = "www.mbed.com"; +/* Example profile definition document for initial attestation token - temporary data*/ +static const char attestation_profile_definition[] = "psa-attest.md"; + +#ifdef __cplusplus +} +#endif + +#endif /* __ATTESTATION_BOOTLOADER_DATA_H__ */ diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IMPL/psa_attestation_stubs.c b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IMPL/psa_attestation_stubs.c new file mode 100755 index 0000000..b36c64a --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IMPL/psa_attestation_stubs.c @@ -0,0 +1,31 @@ +/* +* Copyright (c) 2018-2019 ARM Limited. All rights reserved. +* +* SPDX-License-Identifier: Apache-2.0 +* +* Licensed under the Apache License, Version 2.0 (the License); you may +* not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an AS IS BASIS, WITHOUT +* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include +#include "attestation.h" + +enum psa_attest_err_t +attest_check_memory_access(void *addr, + uint32_t size, + enum attest_memory_access_t access) { + if (size == 0) + { + return PSA_ATTEST_ERR_INVALID_INPUT; + } + return PSA_ATTEST_ERR_SUCCESS; +} diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IMPL/psa_inject_attestation_key_impl.c b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IMPL/psa_inject_attestation_key_impl.c new file mode 100755 index 0000000..c63d93e --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IMPL/psa_inject_attestation_key_impl.c @@ -0,0 +1,108 @@ +/* +* Copyright (c) 2018-2019 ARM Limited. All rights reserved. +* +* SPDX-License-Identifier: Apache-2.0 +* +* Licensed under the Apache License, Version 2.0 (the License); you may +* not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an AS IS BASIS, WITHOUT +* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +#include "psa_inject_attestation_key_impl.h" + +#define ECDSA_P256_KEY_SIZE_IN_BYTES 32 +#define PSA_ATTESTATION_PRIVATE_KEY_ID 17 + +psa_status_t +psa_attestation_inject_key_impl(const uint8_t *key_data, + size_t key_data_length, + psa_key_type_t type, + uint8_t *public_key_data, + size_t public_key_data_size, + size_t *public_key_data_length) +{ + psa_status_t status = PSA_SUCCESS; + size_t key_data_bits = ECDSA_P256_KEY_SIZE_IN_BYTES * 8; + psa_key_handle_t handle = 0; + psa_key_id_t key_id = PSA_ATTESTATION_PRIVATE_KEY_ID; + psa_key_lifetime_t lifetime = PSA_KEY_LIFETIME_PERSISTENT; + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + psa_key_usage_t usage = PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_SIGN | PSA_KEY_USAGE_VERIFY; + psa_key_type_t public_type; + size_t bits; + size_t exported_size = 0; + psa_key_type_t type_key; + +#if defined(MBEDTLS_ECP_C) + + status = psa_open_key(key_id, &handle); + if (status == PSA_SUCCESS) { + /* The key already has been injected */ + goto exit; + } + + psa_set_key_usage_flags(&attributes, usage); + psa_set_key_algorithm(&attributes, PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_256)); + psa_set_key_type(&attributes, type); + psa_set_key_bits(&attributes, key_data_bits); + psa_set_key_lifetime(&attributes, lifetime); + psa_set_key_id(&attributes, key_id); + + if (! PSA_KEY_TYPE_IS_ECC_KEY_PAIR(type)) { + return (PSA_ERROR_INVALID_ARGUMENT); + } + + if (key_data != NULL) { + if (key_data_length != ECDSA_P256_KEY_SIZE_IN_BYTES) { + status = PSA_ERROR_INVALID_ARGUMENT; + goto exit; + } + status = psa_import_key(&attributes, key_data, key_data_length, &handle); + if (status != PSA_SUCCESS) { + goto exit; + } + } else { + /* generating key pair */ + key_data_bits = ECDSA_P256_KEY_SIZE_IN_BYTES * 8; + status = psa_generate_key(&attributes, &handle); + if (status != PSA_SUCCESS) { + goto exit; + } + } + + status = psa_get_key_attributes(handle, &attributes); + if (status != PSA_SUCCESS) { + goto exit; + } + + type_key = psa_get_key_type(&attributes); + public_type = PSA_KEY_TYPE_PUBLIC_KEY_OF_KEY_PAIR(type_key); + bits = psa_get_key_bits(&attributes); + exported_size = PSA_KEY_EXPORT_MAX_SIZE(public_type, bits); + + status = psa_export_public_key(handle, + public_key_data, + public_key_data_size, + public_key_data_length); + if (status != PSA_SUCCESS) { + goto exit; + } + if (*public_key_data_length > exported_size) { + status = PSA_ERROR_INVALID_ARGUMENT; + goto exit; + } + +exit: + psa_close_key(handle); + return (status); +#endif /* MBEDTLS_ECP_C */ + + return (PSA_ERROR_NOT_SUPPORTED); +} diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IMPL/psa_inject_attestation_key_impl.h b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IMPL/psa_inject_attestation_key_impl.h new file mode 100755 index 0000000..de6e1bb --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IMPL/psa_inject_attestation_key_impl.h @@ -0,0 +1,43 @@ +/* +* Copyright (c) 2018-2019 ARM Limited. All rights reserved. +* +* SPDX-License-Identifier: Apache-2.0 +* +* Licensed under the Apache License, Version 2.0 (the License); you may +* not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an AS IS BASIS, WITHOUT +* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#ifndef __PSA_INITIAL_ATTESTATION_IMPL_H__ +#define __PSA_INITIAL_ATTESTATION_IMPL_H__ + +#include "psa/crypto.h" +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + +psa_status_t +psa_attestation_inject_key_impl(const uint8_t *key_data, + size_t key_data_length, + psa_key_type_t type, + uint8_t *public_key_data, + size_t public_key_data_size, + size_t *public_key_data_length); + +#ifdef __cplusplus +} +#endif + +#endif /* __PSA_INITIAL_ATTESTATION_IMPL_H__ */ diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/attest_eat_defines.h b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/attest_eat_defines.h new file mode 100755 index 0000000..002e2a1 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/attest_eat_defines.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2019, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#ifndef __ATTEST_EAT_DEFINES_H__ +#define __ATTEST_EAT_DEFINES_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#define EAT_CBOR_ARM_RANGE_BASE (-75000) +#define EAT_CBOR_ARM_LABEL_PROFILE_DEFINITION (EAT_CBOR_ARM_RANGE_BASE - 0) +#define EAT_CBOR_ARM_LABEL_CLIENT_ID (EAT_CBOR_ARM_RANGE_BASE - 1) +#define EAT_CBOR_ARM_LABEL_SECURITY_LIFECYCLE (EAT_CBOR_ARM_RANGE_BASE - 2) +#define EAT_CBOR_ARM_LABEL_IMPLEMENTATION_ID (EAT_CBOR_ARM_RANGE_BASE - 3) +#define EAT_CBOR_ARM_LABEL_BOOT_SEED (EAT_CBOR_ARM_RANGE_BASE - 4) +#define EAT_CBOR_ARM_LABEL_HW_VERSION (EAT_CBOR_ARM_RANGE_BASE - 5) +#define EAT_CBOR_ARM_LABEL_SW_COMPONENTS (EAT_CBOR_ARM_RANGE_BASE - 6) +#define EAT_CBOR_ARM_LABEL_NO_SW_COMPONENTS (EAT_CBOR_ARM_RANGE_BASE - 7) +#define EAT_CBOR_ARM_LABEL_CHALLENGE (EAT_CBOR_ARM_RANGE_BASE - 8) +#define EAT_CBOR_ARM_LABEL_UEID (EAT_CBOR_ARM_RANGE_BASE - 9) +#define EAT_CBOR_ARM_LABEL_ORIGINATION (EAT_CBOR_ARM_RANGE_BASE - 10) + +#define EAT_CBOR_SW_COMPONENT_MEASUREMENT_TYPE (1) +#define EAT_CBOR_SW_COMPONENT_MEASUREMENT_VALUE (2) +#define EAT_CBOR_SW_COMPONENT_SECURITY_EPOCH (3) +#define EAT_CBOR_SW_COMPONENT_VERSION (4) +#define EAT_CBOR_SW_COMPONENT_SIGNER_ID (5) +#define EAT_CBOR_SW_COMPONENT_MEASUREMENT_DESC (6) + +#ifdef __cplusplus +} +#endif + +#endif /* __ATTEST_EAT_DEFINES_H__ */ diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/attest_token.c b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/attest_token.c new file mode 100755 index 0000000..8cf5f74 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/attest_token.c @@ -0,0 +1,228 @@ +/* + * attest_token.c + * + * Copyright (c) 2018-2019, Laurence Lundblade. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + * See BSD-3-Clause license in README.md + */ + +#include "attest_token.h" +#include "qcbor.h" +#include "t_cose_sign1_sign.h" + + +/** + * \file attest_token.c + * + * \brief Attestation token creation implementation + * + * Outline of token creation. Much of this occurs inside + * t_cose_sign1_init() and t_cose_sign1_finish(). + * + * - Create encoder context + * - Open the CBOR array that hold the \c COSE_Sign1 + * - Write COSE Headers + * - Protected Header + * - Algorithm ID + * - Unprotected Headers + * - Key ID + * - Open payload bstr + * - Write payload data… lots of it… + * - Get bstr that is the encoded payload + * - Compute signature + * - Create a separate encoder context for \c Sig_structure + * - Encode CBOR context identifier + * - Encode protected headers + * - Encode two empty bstr + * - Add one more empty bstr that is a "fake payload" + * - Close off \c Sig_structure + * - Hash all but "fake payload" of \c Sig_structure + * - Get payload bstr ptr and length + * - Continue hash of the real encoded payload + * - Run ECDSA + * - Write signature into the CBOR output + * - Close CBOR array holding the \c COSE_Sign1 + */ + +/* + * \brief Map t_cose error to attestation token error. + * + * \param[in] err The t_cose error to map. + * + * \return the attestation token error. + * + */ +static enum attest_token_err_t t_cose_err_to_attest_err(enum t_cose_err_t err) +{ + switch(err) { + + case T_COSE_SUCCESS: + return ATTEST_TOKEN_ERR_SUCCESS; + + case T_COSE_ERR_UNSUPPORTED_HASH: + return ATTEST_TOKEN_ERR_HASH_UNAVAILABLE; + + default: + /* A lot of the errors are not mapped because they are + * primarily internal errors that should never happen. They + * end up here. + */ + return ATTEST_TOKEN_ERR_GENERAL; + } +} + + +/* + Public function. See attest_token.h + */ +enum attest_token_err_t attest_token_start(struct attest_token_ctx *me, + uint32_t opt_flags, + int32_t key_select, + int32_t cose_alg_id, + const struct useful_buf *out_buf) +{ + /* approximate stack usage on 32-bit machine: 4 bytes */ + enum t_cose_err_t cose_return_value; + enum attest_token_err_t return_value; + + /* Remember some of the configuration values */ + me->opt_flags = opt_flags; + me->key_select = key_select; + + /* Spin up the CBOR encoder */ + QCBOREncode_Init(&(me->cbor_enc_ctx), *out_buf); + + + /* Initialize COSE signer. This will cause the cose headers to be + * encoded and written into out_buf using me->cbor_enc_ctx + */ + cose_return_value = t_cose_sign1_init(&(me->signer_ctx), + opt_flags & + TOKEN_OPT_SHORT_CIRCUIT_SIGN, + cose_alg_id, + key_select, + &(me->cbor_enc_ctx)); + if(cose_return_value) { + return_value = t_cose_err_to_attest_err(cose_return_value); + goto Done; + } + + /* Open the payload-wrapping bstr */ + QCBOREncode_BstrWrap(&(me->cbor_enc_ctx)); + + QCBOREncode_OpenMap(&(me->cbor_enc_ctx)); + + return_value = ATTEST_TOKEN_ERR_SUCCESS; + +Done: + return return_value; +} + + +/* + Public function. See attest_token.h + */ +QCBOREncodeContext *attest_token_borrow_cbor_cntxt(struct attest_token_ctx *me) +{ + return &(me->cbor_enc_ctx); +} + + +/* + Public function. See attest_token.h + */ +void attest_token_add_integer(struct attest_token_ctx *me, + int32_t label, + int64_t Value) +{ + QCBOREncode_AddInt64ToMapN(&(me->cbor_enc_ctx), label, Value); +} + + +/* + Public function. See attest_token.h + */ +void attest_token_add_bstr(struct attest_token_ctx *me, + int32_t label, + const struct useful_buf_c *bstr) +{ + QCBOREncode_AddBytesToMapN(&(me->cbor_enc_ctx), + label, + *bstr); +} + + +/* + Public function. See attest_token.h + */ +void attest_token_add_tstr(struct attest_token_ctx *me, + int32_t label, + const struct useful_buf_c *tstr) +{ + QCBOREncode_AddTextToMapN(&(me->cbor_enc_ctx), label, *tstr); +} + + +/* + See attest_token.h + */ +void attest_token_add_encoded(struct attest_token_ctx *me, + int32_t label, + const struct useful_buf_c *encoded) +{ + QCBOREncode_AddEncodedToMapN(&(me->cbor_enc_ctx), label, *encoded); +} + + +/* + Public function. See attest_token.h + */ +enum attest_token_err_t +attest_token_finish(struct attest_token_ctx *me, + struct useful_buf_c *completed_token) +{ + /* approximate stack usage on 32-bit machine: 4 + 4 + 8 + 8 = 24 */ + enum attest_token_err_t return_value = ATTEST_TOKEN_ERR_SUCCESS; + /* The payload with all the claims that is signed */ + struct useful_buf_c token_payload_ub; + /* The completed and signed encoded cose_sign1 */ + struct useful_buf_c completed_token_ub; + QCBORError qcbor_result; + enum t_cose_err_t cose_return_value; + + QCBOREncode_CloseMap(&(me->cbor_enc_ctx)); + + /* Close off the payload-wrapping bstr. This gives us back the + * pointer and length of the payload that needs to be hashed as + * part of the signature + */ + QCBOREncode_CloseBstrWrap(&(me->cbor_enc_ctx), &token_payload_ub); + + /* Finish off the cose signature. This does all the interesting work of + hashing and signing */ + cose_return_value = + t_cose_sign1_finish(&(me->signer_ctx), token_payload_ub); + if(cose_return_value) { + /* Main errors are invoking the hash or signature */ + return_value = t_cose_err_to_attest_err(cose_return_value); + goto Done; + } + + /* Close off the CBOR encoding and return the completed token */ + qcbor_result = QCBOREncode_Finish(&(me->cbor_enc_ctx), + &completed_token_ub); + if(qcbor_result == QCBOR_ERR_BUFFER_TOO_SMALL) { + return_value = ATTEST_TOKEN_ERR_TOO_SMALL; + } else if (qcbor_result != QCBOR_SUCCESS) { + /* likely from array not closed, too many closes, ... */ + return_value = ATTEST_TOKEN_ERR_CBOR_FORMATTING; + } else { + *completed_token = completed_token_ub; + } + +Done: + return return_value; +} + diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/attest_token.h b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/attest_token.h new file mode 100755 index 0000000..903c42b --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/attest_token.h @@ -0,0 +1,241 @@ +/* + * attest_token.h + * + * Copyright (c) 2018-2019, Laurence Lundblade. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + * See BSD-3-Clause license in README.md + */ + +#ifndef __ATTEST_TOKEN_H__ +#define __ATTEST_TOKEN_H__ + +#include +#include "qcbor.h" +#include "t_cose_sign1_sign.h" + + +/** + * \file attest_token.h + * + * \brief Attestation Token Creation Interface + * + * The context and functions here are the way to create an attestation + * token. The steps are roughly: + * + * -# Creation and initialize an attest_token_ctx indicating the + * options, key and such using attest_token_start(). + * + * -# Use various add methods to fill in the payload with claims. The + * encoding context can also be borrowed for more rich payloads. + * + * -# Call attest_token_finish() to create the signature and finish + * formatting the COSE signed output. + */ + + +/** + Error codes returned from attestation token creation. + */ +enum attest_token_err_t { + /** Success */ + ATTEST_TOKEN_ERR_SUCCESS = 0, + /** The buffer passed in to receive the output is too small. */ + ATTEST_TOKEN_ERR_TOO_SMALL, + /** Something went wrong formatting the CBOR, most likely the + payload has maps or arrays that are not closed. */ + ATTEST_TOKEN_ERR_CBOR_FORMATTING, + /** A general, unspecific error when creating or decoding the + token. */ + ATTEST_TOKEN_ERR_GENERAL, + /** A hash function that is needed to make the token is not + available. */ + ATTEST_TOKEN_ERR_HASH_UNAVAILABLE, + /** CBOR Syntax not well-formed -- a CBOR syntax error. */ + ATTEST_TOKEN_ERR_CBOR_NOT_WELL_FORMED, + /** Bad CBOR structure, for example not a map when was is + required. */ + ATTEST_TOKEN_ERR_CBOR_STRUCTURE, + /** Bad CBOR type, for example an not a text string, when a text + string is required. */ + ATTETST_TOKEN_ERR_CBOR_TYPE, + /** Integer too large, for example an \c int32_t is required, but + value only fits in \c int64_t */ + ATTEST_TOKEN_ERR_INTEGER_VALUE, + /** Something is wrong with the COSE signing structure, missing + headers or such. */ + ATTEST_TOKEN_ERR_COSE_SIGN1_FORMAT, + /** COSE signature is invalid, data is corrupted. */ + ATTEST_TOKEN_ERR_COSE_SIGN1_VALIDATION, + /** The signing algorithm is not supported. */ + ATTEST_TOKEN_ERR_UNSUPPORTED_SIG_ALG, + /** Out of memory. */ + ATTEST_TOKEN_ERR_INSUFFICIENT_MEMORY, + /** Tampering detected in cryptographic function. */ + ATTEST_TOKEN_ERR_TAMPERING_DETECTED, + /** Verification key is not found or of wrong type. */ + ATTEST_TOKEN_ERR_VERIFICATION_KEY +}; + + + +/** + * Request that the claims internally generated not be added to the + * token. This is a test mode that results in a static token that + * never changes. Only the nonce is included. The nonce is under + * the callers control unlike the other claims. + */ +#define TOKEN_OPT_OMIT_CLAIMS 0x40000000 + + +/** + * A special test mode where a proper signature is not produced. In + * its place there is a concatenation of hashes of the payload to be + * the same size as the signature. This works and can be used to + * verify all of the SW stack except the public signature part. The + * token has no security value in this mode because anyone can + * replicate it. */ +#define TOKEN_OPT_SHORT_CIRCUIT_SIGN 0x80000000 + + +/** + * The context for creating an attestation token. The caller of + * attest_token must create one of these and pass it to the functions + * here. It is small enough that it can go on the stack. It is most of + * the memory needed to create a token except the output buffer and + * any memory requirements for the cryptographic operations. + * + * The structure is opaque for the caller. + * + * This is roughly 148 + 8 + 32 = 188 bytes + */ +struct attest_token_ctx { + /* Private data structure */ + QCBOREncodeContext cbor_enc_ctx; + uint32_t opt_flags; + int32_t key_select; + struct t_cose_sign1_ctx signer_ctx; +}; + + +/** + * \brief Initialize a token creation context. + * + * \param[in] me The token creation context to be initialized. + * \param[in] opt_flags Flags to select different custom options, + for example \ref TOKEN_OPT_OMIT_CLAIMS. + * \param[in] key_select Selects which attestation key to sign with. + * \param[in] cose_alg_id The algorithm to sign with. The IDs are + * defined in [COSE (RFC 8152)] + * (https://tools.ietf.org/html/rfc8152) or + * in the [IANA COSE Registry] + * (https://www.iana.org/assignments/cose/cose.xhtml). + * \param[out] out_buffer The output buffer to write the encoded token into. + * + * \return one of the \ref attest_token_err_t errors. + * + * The size of the buffer in \c out_buffer->len + * determines the size of the token that can be created. It must be + * able to hold the final encoded and signed token. The data encoding + * overhead is just that of CBOR. The signing overhead depends on the + * signing key size. It is about 150 bytes for 256-bit ECDSA. + * + * If \c out_buffer->ptr is \c NULL and \c out_buffer_ptr->len is + * large like \c UINT32_MAX no token will be created but the length of + * the token that would be created will be in \c completed_token as + * returned by attest_token_finish(). None of the cryptographic + * functions run during this, but the sizes of what they would output + * is taken into account. + */ +enum attest_token_err_t +attest_token_start(struct attest_token_ctx *me, + uint32_t opt_flags, + int32_t key_select, + int32_t cose_alg_id, + const struct useful_buf *out_buffer); + + + +/** + * \brief Get a copy of the CBOR encoding context + * + * \param[in] me Token creation context. + * + * \return The CBOR encoding context + * + * Allows the caller to encode CBOR right into the output buffer using + * any of the \c QCBOREncode_AddXXXX() methods. Anything added here + * will be part of the payload that gets hashed. This can be used to + * make complex CBOR structures. All open arrays and maps must be + * close before calling any other \c attest_token methods. \c + * QCBOREncode_Finish() should not be closed on this context. + */ +QCBOREncodeContext *attest_token_borrow_cbor_cntxt(struct attest_token_ctx *me); + +/** + * \brief Add a 64-bit signed integer claim + * + * \param[in] me Token creation context. + * \param[in] label Integer label for claim. + * \param[in] value The integer claim data. + */ +void attest_token_add_integer(struct attest_token_ctx *me, + int32_t label, + int64_t value); + +/** + * \brief Add a binary string claim + * + * \param[in] me Token creation context. + * \param[in] label Integer label for claim. + * \param[in] value The binary claim data. + */ +void attest_token_add_bstr(struct attest_token_ctx *me, + int32_t label, + const struct useful_buf_c *value); + +/** + * \brief Add a text string claim + * + * \param[in] me Token creation context. + * \param[in] label Integer label for claim. + * \param[in] value The text claim data. + */ +void attest_token_add_tstr(struct attest_token_ctx *me, + int32_t label, + const struct useful_buf_c *value); + +/** + * \brief Add some already-encoded CBOR to payload + * + * \param[in] me Token creation context. + * \param[in] label Integer label for claim. + * \param[in] encoded The already-encoded CBOR. + * + * Encoded CBOR must be a full map or full array or a non-aggregate + * type. It cannot be a partial map or array. It can be nested maps + * and arrays, but they must all be complete. + */ +void attest_token_add_encoded(struct attest_token_ctx *me, + int32_t label, + const struct useful_buf_c *encoded); + + +/** + * \brief Finish the token, complete the signing and get the result + * + * \param[in] me Token Creation Context. + * \param[out] completed_token Pointer and length to completed token. + * + * \return one of the \ref attest_token_err_t errors. + * + * This completes the token after the payload has been added. When + * this is called the signing algorithm is run and the final + * formatting of the token is completed. + */ +enum attest_token_err_t +attest_token_finish(struct attest_token_ctx *me, + struct useful_buf_c *completed_token); + +#endif /* __ATTEST_TOKEN_H__ */ diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/attestation_core.c b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/attestation_core.c new file mode 100755 index 0000000..a7e46da --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/attestation_core.c @@ -0,0 +1,1032 @@ +/* + * Copyright (c) 2018-2019, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#include +#include +#include +#include "tfm_client.h" +#include "attestation.h" +#include "tfm_impl/tfm_boot_status.h" +#include "tfm_plat_defs.h" +#include "tfm_plat_device_id.h" +#include "tfm_plat_boot_seed.h" +#include "tfm_attest_hal.h" +#include "attest_token.h" +#include "attest_eat_defines.h" +#include "t_cose_defines.h" +#include "tfm_memory_utils.h" + +#define MAX_BOOT_STATUS 512 + +/* Indicates how to encode SW components' measurements in the CBOR map */ +#define EAT_SW_COMPONENT_NESTED 1 /* Nested map */ +#define EAT_SW_COMPONENT_NOT_NESTED 0 /* Flat structure */ + +/* Indicates that the boot status does not contain any SW components' + * measurement + */ +#define NO_SW_COMPONENT_FIXED_VALUE 1 + +/*! + * \var boot_status + * + * \brief Array variable to store the boot status in service's memory. + * + * \details Boot status comes from the secure bootloader and primarily stored + * on a memory area which is shared between bootloader and SPM. + * SPM provides the \ref tfm_core_get_boot_data() API to retrieve + * the service related data from shared area. + */ + +/* Enforcement of 4 byte alignment, which is checked by TF-M SPM */ +__attribute__ ((aligned(4))) +static uint8_t boot_status[MAX_BOOT_STATUS]; + +enum psa_attest_err_t attest_init(void) +{ + enum psa_attest_err_t res; + + res = attest_get_boot_data(TLV_MAJOR_IAS, boot_status, MAX_BOOT_STATUS); + + return res; +} + +/*! + * \brief Static function to map return values between \ref attest_token_err_t + * and \ref psa_attest_err_t + * + * \param[in] token_err Token encoding return value + * + * \return Returns error code as specified in \ref psa_attest_err_t + */ +static inline enum psa_attest_err_t +error_mapping(enum attest_token_err_t token_err) +{ + switch (token_err) { + case ATTEST_TOKEN_ERR_SUCCESS: + return PSA_ATTEST_ERR_SUCCESS; + break; + case ATTEST_TOKEN_ERR_TOO_SMALL: + return PSA_ATTEST_ERR_TOKEN_BUFFER_OVERFLOW; + break; + default: + return PSA_ATTEST_ERR_GENERAL; + } +} + +/*! + * \brief Static function to convert a pointer and size info to unsigned + * integer number. Max 32bits unsigned integers are supported. + * + * This implementation assumes that the endianness of the sender and receiver + * of the data is the same because they are actually running on the same CPU + * instance. If this assumption is not true than this function must be + * refactored accordingly. + * + * \param[in] int_ptr Pointer to the unsigned integer + * \param[in] len Size of the unsigned integers in bytes + * \param[in] value Pointer where to store the converted value + * + * \return Returns 0 on success and -1 on error. + */ +static inline int32_t get_uint(const void *int_ptr, + size_t len, + uint32_t *value) +{ + uint16_t uint16; + + switch (len) { + case 1: + *value = (uint32_t)(*(uint8_t *)(int_ptr)); + break; + case 2: + /* Avoid unaligned access */ + tfm_memcpy(&uint16, int_ptr, sizeof(uint16)); + *value = (uint32_t)uint16; + break; + case 4: + /* Avoid unaligned access */ + tfm_memcpy(value, int_ptr, sizeof(uint32_t)); + break; + default: + return -1; + } + + return 0; +} +/*! + * \brief Static function to look up all entires in the shared data area + * (boot status) which belong to a specific module. + * + * \param[in] module The identifier of SW module to look up based on this + * \param[out] claim The type of SW module's attribute + * \param[out] tlv_len Length of the shared data entry + * \param[in/out] tlv_ptr Pointer to the shared data entry. If its value NULL as + * input then it will starts the look up from the + * beginning of the shared data section. If not NULL then + * it continue look up from the next entry. It returns + * the address of next found entry which belongs to + * module. + * + * \retval -1 Error, boot status is malformed + * \retval 0 Entry not found + * \retval 1 Entry found + */ +static int32_t attest_get_tlv_by_module(uint8_t module, + uint8_t *claim, + uint16_t *tlv_len, + uint8_t **tlv_ptr) +{ + struct shared_data_tlv_header *tlv_header; + struct shared_data_tlv_entry tlv_entry; + uint8_t *tlv_end; + uint8_t *tlv_curr; + + tlv_header = (struct shared_data_tlv_header *)boot_status; + if (tlv_header->tlv_magic != SHARED_DATA_TLV_INFO_MAGIC) { + return -1; + } + + /* Get the boundaries of TLV section where to lookup*/ + tlv_end = (uint8_t *)boot_status + tlv_header->tlv_tot_len; + if (*tlv_ptr == NULL) { + /* At first call set to the beginning of the TLV section */ + tlv_curr = (uint8_t *)boot_status + SHARED_DATA_HEADER_SIZE; + } else { + /* Any subsequent call set to the next TLV entry */ + tfm_memcpy(&tlv_entry, *tlv_ptr, SHARED_DATA_ENTRY_HEADER_SIZE); + tlv_curr = (*tlv_ptr) + tlv_entry.tlv_len; + } + + /* Iterates over the TLV section and returns the address and size of TLVs + * with requested module identifier + */ + for (; tlv_curr < tlv_end; tlv_curr += tlv_entry.tlv_len) { + /* Create local copy to avoid unaligned access */ + tfm_memcpy(&tlv_entry, tlv_curr, SHARED_DATA_ENTRY_HEADER_SIZE); + if (GET_IAS_MODULE(tlv_entry.tlv_type) == module) { + *claim = GET_IAS_CLAIM(tlv_entry.tlv_type); + *tlv_ptr = tlv_curr; + *tlv_len = tlv_entry.tlv_len; + return 1; + } + } + + return 0; +} + +/*! + * \brief Static function to look up specific claim belongs to SW_GENERAL module + * + * \param[in] claim The claim ID to look for + * \param[out] tlv_len Length of the shared data entry + * \param[out] tlv_ptr Pointer to a shared data entry which belongs to the + * SW_GENERAL module. + * + * \retval -1 Error, boot status is malformed + * \retval 0 Entry not found + * \retval 1 Entry found + */ +static int32_t attest_get_tlv_by_id(uint8_t claim, + uint16_t *tlv_len, + uint8_t **tlv_ptr) +{ + uint8_t tlv_id; + uint8_t module = SW_GENERAL; + int32_t found; + + /* Ensure that look up starting from the beginning of the boot status */ + *tlv_ptr = NULL; + + /* Look up specific TLV entry which belongs to SW_GENERAL module */ + do { + /* Look up next entry */ + found = attest_get_tlv_by_module(module, &tlv_id, + tlv_len, tlv_ptr); + if (found != 1) { + break; + } + /* At least one entry was found which belongs to SW_GENERAL, + * check whether this one is looked for + */ + if (claim == tlv_id) { + break; + } + } while (found == 1); + + return found; +} + +/*! + * \brief Static function to add SW component related claims to attestation + * token in CBOR format. + * + * This function translates between TLV and CBOR encoding. + * + * \param[in] token_ctx Attestation token encoding context + * \param[in] tlv_id The ID of claim + * \param[in] claim_value A structure which carries a pointer and size about + * the data item to be added to the token + * + * \return Returns error code as specified in \ref psa_attest_err_t + */ +static enum psa_attest_err_t +attest_add_sw_component_claim(struct attest_token_ctx *token_ctx, + uint8_t tlv_id, + const struct useful_buf_c *claim_value) +{ + int32_t res; + uint32_t value; + + switch (tlv_id) { + case SW_MEASURE_VALUE: + attest_token_add_bstr(token_ctx, + EAT_CBOR_SW_COMPONENT_MEASUREMENT_VALUE, + claim_value); + break; + case SW_MEASURE_TYPE: + attest_token_add_tstr(token_ctx, + EAT_CBOR_SW_COMPONENT_MEASUREMENT_DESC, + claim_value); + break; + case SW_VERSION: + attest_token_add_tstr(token_ctx, + EAT_CBOR_SW_COMPONENT_VERSION, + claim_value); + break; + case SW_SIGNER_ID: + attest_token_add_bstr(token_ctx, + EAT_CBOR_SW_COMPONENT_SIGNER_ID, + claim_value); + break; + case SW_EPOCH: + res = get_uint(claim_value->ptr, claim_value->len, &value); + if (res) { + return PSA_ATTEST_ERR_GENERAL; + } + attest_token_add_integer(token_ctx, + EAT_CBOR_SW_COMPONENT_SECURITY_EPOCH, + (int64_t)value); + break; + case SW_TYPE: + attest_token_add_tstr(token_ctx, + EAT_CBOR_SW_COMPONENT_MEASUREMENT_TYPE, + claim_value); + break; + default: + return PSA_ATTEST_ERR_GENERAL; + } + + return PSA_ATTEST_ERR_SUCCESS; +} + +/*! + * \brief Static function to add the measurement data of a single SW components + * to the attestation token. + * + * \param[in] token_ctx Token encoding context + * \param[in] module SW component identifier + * \param[in] tlv_address Address of the first TLV entry in the boot status, + * which belongs to this SW component. + * \param[in] nested_map Flag to indicate that how to encode the SW component + * measurement data: nested map or non-nested map. + * + * \return Returns error code as specified in \ref psa_attest_err_t + */ +static enum psa_attest_err_t +attest_add_single_sw_measurment(struct attest_token_ctx *token_ctx, + uint32_t module, + uint8_t *tlv_address, + uint32_t nested_map) +{ + struct shared_data_tlv_entry tlv_entry; + uint16_t tlv_len; + uint8_t tlv_id; + uint8_t *tlv_ptr = tlv_address; + int32_t found = 1; + struct useful_buf_c claim_value; + enum psa_attest_err_t res; + QCBOREncodeContext *cbor_encode_ctx; + + /* Create local copy to avoid unaligned access */ + tfm_memcpy(&tlv_entry, tlv_address, SHARED_DATA_ENTRY_HEADER_SIZE); + tlv_len = tlv_entry.tlv_len; + tlv_id = GET_IAS_CLAIM(tlv_entry.tlv_type); + + cbor_encode_ctx = attest_token_borrow_cbor_cntxt(token_ctx); + + /* Open nested map for SW component measurement claims */ + if (nested_map) { + QCBOREncode_OpenMapInMapN(cbor_encode_ctx, + EAT_CBOR_SW_COMPONENT_MEASUREMENT_VALUE); + } + + /* Look up all measurement TLV entry which belongs to the SW component */ + while (found) { + /* Here only measurement claims are added to the token */ + if (GET_IAS_MEASUREMENT_CLAIM(tlv_id)) { + claim_value.ptr = tlv_ptr + SHARED_DATA_ENTRY_HEADER_SIZE; + claim_value.len = tlv_len - SHARED_DATA_ENTRY_HEADER_SIZE; + res = attest_add_sw_component_claim(token_ctx, + tlv_id, + &claim_value); + if (res != PSA_ATTEST_ERR_SUCCESS) { + return res; + } + } + + /* Look up next entry it can be non-measurement claim*/ + found = attest_get_tlv_by_module(module, &tlv_id, + &tlv_len, &tlv_ptr); + if (found == -1) { + return PSA_ATTEST_ERR_CLAIM_UNAVAILABLE; + } + } + + if (nested_map) { + QCBOREncode_CloseMap(cbor_encode_ctx); + } + + return PSA_ATTEST_ERR_SUCCESS; +} + +/*! + * \brief Static function to add the claims of a single SW components to the + * attestation token. + * + * \param[in] token_ctx Token encoding context + * \param[in] module SW component identifier + * \param[in] tlv_address Address of the first TLV entry in the boot status, + * which belongs to this SW component. + * + * \return Returns error code as specified in \ref psa_attest_err_t + */ +static enum psa_attest_err_t +attest_add_single_sw_component(struct attest_token_ctx *token_ctx, + uint32_t module, + uint8_t *tlv_address) +{ + struct shared_data_tlv_entry tlv_entry; + uint16_t tlv_len; + uint8_t tlv_id; + uint8_t *tlv_ptr = tlv_address; + int32_t found = 1; + uint32_t measurement_claim_cnt = 0; + struct useful_buf_c claim_value; + QCBOREncodeContext *cbor_encode_ctx; + + /* Create local copy to avoid unaligned access */ + tfm_memcpy(&tlv_entry, tlv_address, SHARED_DATA_ENTRY_HEADER_SIZE); + tlv_len = tlv_entry.tlv_len; + tlv_id = GET_IAS_CLAIM(tlv_entry.tlv_type); + + /* Open map which stores claims belong to a SW component */ + cbor_encode_ctx = attest_token_borrow_cbor_cntxt(token_ctx); + QCBOREncode_OpenMap(cbor_encode_ctx); + + /*Look up all TLV entry which belongs to the same SW component */ + while (found) { + /* Check whether claim is measurement claim */ + if (GET_IAS_MEASUREMENT_CLAIM(tlv_id)) { + if (measurement_claim_cnt == 0) { + /* Call only once when first measurement claim found */ + measurement_claim_cnt++; + attest_add_single_sw_measurment(token_ctx, + module, + tlv_ptr, + EAT_SW_COMPONENT_NOT_NESTED); + } + } else { + /* Adding top level claims */ + claim_value.ptr = tlv_ptr + SHARED_DATA_ENTRY_HEADER_SIZE; + claim_value.len = tlv_len - SHARED_DATA_ENTRY_HEADER_SIZE; + attest_add_sw_component_claim(token_ctx, tlv_id, &claim_value); + } + + /* Look up next entry which belongs to SW component */ + found = attest_get_tlv_by_module(module, &tlv_id, + &tlv_len, &tlv_ptr); + if (found == -1) { + return PSA_ATTEST_ERR_CLAIM_UNAVAILABLE; + } + } + + /* Close map which stores claims belong to a SW component */ + QCBOREncode_CloseMap(cbor_encode_ctx); + + return PSA_ATTEST_ERR_SUCCESS; +} + +/*! + * \brief Static function to add the claims of all SW components to the + * attestation token. + * + * \param[in] token_ctx Token encoding context + * + * \return Returns error code as specified in \ref psa_attest_err_t + */ +static enum psa_attest_err_t +attest_add_all_sw_components(struct attest_token_ctx *token_ctx) +{ + uint16_t tlv_len; + uint8_t *tlv_ptr; + uint8_t tlv_id; + int32_t found; + uint32_t cnt = 0; + uint32_t module; + QCBOREncodeContext *cbor_encode_ctx; + + /* Starting from module 1, because module 0 contains general claims which + * are not related to SW module(i.e: boot_seed, etc.) + */ + for (module = 1; module < SW_MAX; ++module) { + /* Indicates to restart the look up from the beginning of the shared + * data section + */ + tlv_ptr = NULL; + + /* Look up the first TLV entry which belongs to the SW module */ + found = attest_get_tlv_by_module(module, &tlv_id, + &tlv_len, &tlv_ptr); + if (found == -1) { + return PSA_ATTEST_ERR_CLAIM_UNAVAILABLE; + } + + if (found == 1) { + cnt++; + if (cnt == 1) { + /* Open array which stores SW components claims */ + cbor_encode_ctx = attest_token_borrow_cbor_cntxt(token_ctx); + QCBOREncode_OpenArrayInMapN(cbor_encode_ctx, + EAT_CBOR_ARM_LABEL_SW_COMPONENTS); + } + attest_add_single_sw_component(token_ctx, module, tlv_ptr); + } + } + + if (cnt != 0) { + /* Close array which stores SW components claims*/ + QCBOREncode_CloseArray(cbor_encode_ctx); + } else { + /* If there is not any SW components' measurement in the boot status + * then include this claim to indicate that this state is intentional + */ + attest_token_add_integer(token_ctx, + EAT_CBOR_ARM_LABEL_NO_SW_COMPONENTS, + (int64_t)NO_SW_COMPONENT_FIXED_VALUE); + } + + return PSA_ATTEST_ERR_SUCCESS; +} + +/*! + * \brief Static function to add boot seed claim to attestation token. + * + * \param[in] token_ctx Token encoding context + * + * \return Returns error code as specified in \ref psa_attest_err_t + */ +static enum psa_attest_err_t +attest_add_boot_seed_claim(struct attest_token_ctx *token_ctx) +{ + /* FixMe: Enforcement of 4 byte alignment can be removed as soon as memory + * type is configured in the MPU to be normal, instead of device, + * which prohibits unaligned access. + */ + __attribute__ ((aligned(4))) + uint8_t boot_seed[BOOT_SEED_SIZE]; + enum tfm_plat_err_t res; + struct useful_buf_c claim_value = {0}; + uint16_t tlv_len; + uint8_t *tlv_ptr = NULL; + int32_t found = 0; + + /* First look up BOOT_SEED in boot status, it might comes from bootloader */ + found = attest_get_tlv_by_id(BOOT_SEED, &tlv_len, &tlv_ptr); + if (found == 1) { + claim_value.ptr = tlv_ptr + SHARED_DATA_ENTRY_HEADER_SIZE; + claim_value.len = tlv_len - SHARED_DATA_ENTRY_HEADER_SIZE; + } else { + /* If not found in boot status then use callback function to get it + * from runtime SW + */ + res = tfm_plat_get_boot_seed(sizeof(boot_seed), boot_seed); + if (res != TFM_PLAT_ERR_SUCCESS) { + return PSA_ATTEST_ERR_CLAIM_UNAVAILABLE; + } + claim_value.ptr = boot_seed; + claim_value.len = BOOT_SEED_SIZE; + } + + attest_token_add_bstr(token_ctx, + EAT_CBOR_ARM_LABEL_BOOT_SEED, + &claim_value); + + return PSA_ATTEST_ERR_SUCCESS; +} + +/* FixMe: Remove this #if when MPU will be configured properly. Currently + * in case of TFM_LVL == 3 unaligned access triggers a usage fault + * exception. + */ +#if !defined(TFM_LVL) || (TFM_LVL == 1) +/*! + * \brief Static function to add instance id claim to attestation token. + * + * \param[in] token_ctx Token encoding context + * + * \return Returns error code as specified in \ref psa_attest_err_t + */ +static enum psa_attest_err_t +attest_add_instance_id_claim(struct attest_token_ctx *token_ctx) +{ + /* FixMe: Enforcement of 4 byte alignment can be removed as soon as memory + * type is configured in the MPU to be normal, instead of device, + * which prohibits unaligned access. + */ + __attribute__ ((aligned(4))) + uint8_t instance_id[INSTANCE_ID_MAX_SIZE]; + enum tfm_plat_err_t res_plat; + uint32_t size = sizeof(instance_id); + struct useful_buf_c claim_value; + + res_plat = tfm_plat_get_instance_id(&size, instance_id); + if (res_plat != TFM_PLAT_ERR_SUCCESS) { + return PSA_ATTEST_ERR_CLAIM_UNAVAILABLE; + } + + claim_value.ptr = instance_id; + claim_value.len = size; + attest_token_add_bstr(token_ctx, + EAT_CBOR_ARM_LABEL_UEID, + &claim_value); + + return PSA_ATTEST_ERR_SUCCESS; +} + +/*! + * \brief Static function to add implementation id claim to attestation token. + * + * \param[in] token_ctx Token encoding context + * + * \return Returns error code as specified in \ref psa_attest_err_t + */ +static enum psa_attest_err_t +attest_add_implementation_id_claim(struct attest_token_ctx *token_ctx) +{ + /* FixMe: Enforcement of 4 byte alignment can be removed as soon as memory + * type is configured in the MPU to be normal, instead of device, + * which prohibits unaligned access. + */ + __attribute__ ((aligned(4))) + uint8_t implementation_id[IMPLEMENTATION_ID_MAX_SIZE]; + enum tfm_plat_err_t res_plat; + uint32_t size = sizeof(implementation_id); + struct useful_buf_c claim_value; + + res_plat = tfm_plat_get_implementation_id(&size, implementation_id); + if (res_plat != TFM_PLAT_ERR_SUCCESS) { + return PSA_ATTEST_ERR_CLAIM_UNAVAILABLE; + } + + claim_value.ptr = implementation_id; + claim_value.len = size; + attest_token_add_bstr(token_ctx, + EAT_CBOR_ARM_LABEL_IMPLEMENTATION_ID, + &claim_value); + + return PSA_ATTEST_ERR_SUCCESS; +} + +/*! + * \brief Static function to add hardware version claim to attestation token. + * + * \param[in] token_ctx Token encoding context + * + * \return Returns error code as specified in \ref psa_attest_err_t + */ +static enum psa_attest_err_t +attest_add_hw_version_claim(struct attest_token_ctx *token_ctx) +{ + /* FixMe: Enforcement of 4 byte alignment can be removed as soon as memory + * type is configured in the MPU to be normal, instead of device, + * which prohibits unaligned access. + */ + __attribute__ ((aligned(4))) + uint8_t hw_version[HW_VERSION_MAX_SIZE]; + enum tfm_plat_err_t res_plat; + uint32_t size = sizeof(hw_version); + struct useful_buf_c claim_value = {0}; + uint16_t tlv_len; + uint8_t *tlv_ptr = NULL; + int32_t found = 0; + + /* First look up HW version in boot status, it might comes + * from bootloader + */ + found = attest_get_tlv_by_id(HW_VERSION, &tlv_len, &tlv_ptr); + if (found == 1) { + claim_value.ptr = tlv_ptr + SHARED_DATA_ENTRY_HEADER_SIZE; + claim_value.len = tlv_len - SHARED_DATA_ENTRY_HEADER_SIZE; + } else { + /* If not found in boot status then use callback function to get it + * from runtime SW + */ + res_plat = tfm_plat_get_hw_version(&size, hw_version); + if (res_plat != TFM_PLAT_ERR_SUCCESS) { + return PSA_ATTEST_ERR_CLAIM_UNAVAILABLE; + } + claim_value.ptr = hw_version; + claim_value.len = size; + } + + attest_token_add_tstr(token_ctx, + EAT_CBOR_ARM_LABEL_HW_VERSION, + &claim_value); + + return PSA_ATTEST_ERR_SUCCESS; +} +#endif + +/*! + * \brief Static function to add caller id claim to attestation token. + * + * \param[in] token_ctx Token encoding context + * + * \return Returns error code as specified in \ref psa_attest_err_t + */ +static enum psa_attest_err_t +attest_add_caller_id_claim(struct attest_token_ctx *token_ctx) +{ + enum psa_attest_err_t res; + int32_t caller_id; + + res = attest_get_caller_client_id(&caller_id); + if (res != PSA_ATTEST_ERR_SUCCESS) { + return res; + } + + attest_token_add_integer(token_ctx, + EAT_CBOR_ARM_LABEL_CLIENT_ID, + (int64_t)caller_id); + + return PSA_ATTEST_ERR_SUCCESS; +} + +/*! + * \brief Static function to add security lifecycle claim to attestation token. + * + * \param[in] token_ctx Token encoding context + * + * \return Returns error code as specified in \ref psa_attest_err_t + */ + +static enum psa_attest_err_t +attest_add_security_lifecycle_claim(struct attest_token_ctx *token_ctx) +{ + enum tfm_security_lifecycle_t security_lifecycle; + uint32_t slc_value; + int32_t res; + struct useful_buf_c claim_value = {0}; + uint16_t tlv_len; + uint8_t *tlv_ptr = NULL; + int32_t found = 0; + + /* First look up lifecycle state in boot status, it might comes + * from bootloader + */ + found = attest_get_tlv_by_id(SECURITY_LIFECYCLE, &tlv_len, &tlv_ptr); + if (found == 1) { + claim_value.ptr = tlv_ptr + SHARED_DATA_ENTRY_HEADER_SIZE; + claim_value.len = tlv_len - SHARED_DATA_ENTRY_HEADER_SIZE; + res = get_uint(claim_value.ptr, claim_value.len, &slc_value); + if (res) { + return PSA_ATTEST_ERR_GENERAL; + } + security_lifecycle = (enum tfm_security_lifecycle_t)slc_value; + } else { + /* If not found in boot status then use callback function to get it + * from runtime SW + */ + security_lifecycle = tfm_attest_hal_get_security_lifecycle(); + } + + /* Sanity check */ + if (security_lifecycle < TFM_SLC_UNKNOWN || + security_lifecycle > TFM_SLC_DECOMMISSIONED) { + return PSA_ATTEST_ERR_GENERAL; + } + + attest_token_add_integer(token_ctx, + EAT_CBOR_ARM_LABEL_SECURITY_LIFECYCLE, + (int64_t)security_lifecycle); + + return PSA_ATTEST_ERR_SUCCESS; +} + +/*! + * \brief Static function to add challenge claim to attestation token. + * + * \param[in] token_ctx Token encoding context + * \param[in] challenge Pointer to buffer which stores the challenge + * + * \return Returns error code as specified in \ref psa_attest_err_t + */ +static enum psa_attest_err_t +attest_add_challenge_claim(struct attest_token_ctx *token_ctx, + const struct useful_buf_c *challenge) +{ + attest_token_add_bstr(token_ctx, EAT_CBOR_ARM_LABEL_CHALLENGE, challenge); + + return PSA_ATTEST_ERR_SUCCESS; +} + +/*! + * \brief Static function to add the verification service indicator claim + * to the attestation token. + * + * \param[in] token_ctx Token encoding context + * + * \return Returns error code as specified in \ref psa_attest_err_t + */ +static enum psa_attest_err_t +attest_add_verification_service(struct attest_token_ctx *token_ctx) +{ + struct useful_buf_c service; + uint32_t size; + + service.ptr = tfm_attest_hal_get_verification_service(&size); + + if (service.ptr) { + service.len = size; + attest_token_add_tstr(token_ctx, + EAT_CBOR_ARM_LABEL_ORIGINATION, + &service); + } + + return PSA_ATTEST_ERR_SUCCESS; +} + +/*! + * \brief Static function to add the name of the profile definition document + * + * \param[in] token_ctx Token encoding context + * + * \return Returns error code as specified in \ref psa_attest_err_t + */ +static enum psa_attest_err_t +attest_add_profile_definition(struct attest_token_ctx *token_ctx) +{ + struct useful_buf_c profile; + uint32_t size; + + profile.ptr = tfm_attest_hal_get_profile_definition(&size); + + if (profile.ptr) { + profile.len = size; + attest_token_add_tstr(token_ctx, + EAT_CBOR_ARM_LABEL_PROFILE_DEFINITION, + &profile); + } + + return PSA_ATTEST_ERR_SUCCESS; +} + +/*! + * \brief Static function to verify the input challenge size + * + * Only discrete sizes are accepted. + * + * \param[in] challenge_size Size of challenge object in bytes. + * + * \retval PSA_ATTEST_ERR_SUCCESS + * \retval PSA_ATTEST_ERR_INVALID_INPUT + */ +static enum psa_attest_err_t attest_verify_challenge_size(size_t challenge_size) +{ + switch (challenge_size) { + /* Intentional fall through */ + case PSA_INITIAL_ATTEST_CHALLENGE_SIZE_32: + case PSA_INITIAL_ATTEST_CHALLENGE_SIZE_48: + case PSA_INITIAL_ATTEST_CHALLENGE_SIZE_64: + case (PSA_INITIAL_ATTEST_CHALLENGE_SIZE_32 + 4): /* Test purpose */ + return PSA_ATTEST_ERR_SUCCESS; + } + + return PSA_ATTEST_ERR_INVALID_INPUT; +} + +/*! + * \brief Static function to create the initial attestation token + * + * \param[in] challenge Structure to carry the challenge value: + * pointer + challeng's length + * \param[in] token Structure to carry the token info, where to + * create it: pointer + buffer's length + * \param[out] completed_token Structure to carry the info about the created + * token: pointer + final token's length + * + * \return Returns error code as specified in \ref psa_attest_err_t + */ +static enum psa_attest_err_t +attest_create_token(struct useful_buf_c *challenge, + struct useful_buf *token, + struct useful_buf_c *completed_token) +{ + enum psa_attest_err_t attest_err = PSA_ATTEST_ERR_SUCCESS; + enum attest_token_err_t token_err; + struct attest_token_ctx attest_token_ctx; + int32_t key_select; + uint32_t option_flags = 0; + + if (challenge->len == 36) { + /* FixMe: Special challenge with option flags appended. This might can + * be removed when the public API can take option_flags. + */ + option_flags = *(uint32_t *)((uint8_t*)challenge->ptr + 32); + challenge->len = 32; + } + + /* Lower three bits are the key select */ + key_select = option_flags & 0x7; + + /* Get started creating the token. This sets up the CBOR and COSE contexts + * which causes the COSE headers to be constructed. + */ + token_err = attest_token_start(&attest_token_ctx, + option_flags, /* option_flags */ + key_select, /* key_select */ + COSE_ALGORITHM_ES256, /* alg_select */ + token); + + if (token_err != ATTEST_TOKEN_ERR_SUCCESS) { + attest_err = error_mapping(token_err); + goto error; + } + + attest_err = attest_add_challenge_claim(&attest_token_ctx, + challenge); + if (attest_err != PSA_ATTEST_ERR_SUCCESS) { + goto error; + } + + if (!(option_flags & TOKEN_OPT_OMIT_CLAIMS)) { + attest_err = attest_add_boot_seed_claim(&attest_token_ctx); + if (attest_err != PSA_ATTEST_ERR_SUCCESS) { + goto error; + } + + attest_err = attest_add_verification_service(&attest_token_ctx); + if (attest_err != PSA_ATTEST_ERR_SUCCESS) { + goto error; + } + + attest_err = attest_add_profile_definition(&attest_token_ctx); + if (attest_err != PSA_ATTEST_ERR_SUCCESS) { + goto error; + } + + /* FixMe: Remove this #if when MPU will be configured properly. + * Currently in case of TFM_LVL == 3 unaligned access triggers + * a usage fault exception. + */ +#if !defined(TFM_LVL) || (TFM_LVL == 1) + attest_err = attest_add_instance_id_claim(&attest_token_ctx); + if (attest_err != PSA_ATTEST_ERR_SUCCESS) { + goto error; + } + + attest_err = attest_add_hw_version_claim(&attest_token_ctx); + if (attest_err != PSA_ATTEST_ERR_SUCCESS) { + goto error; + } + + attest_err = attest_add_implementation_id_claim(&attest_token_ctx); + if (attest_err != PSA_ATTEST_ERR_SUCCESS) { + goto error; + } +#endif + + attest_err = attest_add_caller_id_claim(&attest_token_ctx); + if (attest_err != PSA_ATTEST_ERR_SUCCESS) { + goto error; + } + + attest_err = attest_add_security_lifecycle_claim(&attest_token_ctx); + if (attest_err != PSA_ATTEST_ERR_SUCCESS) { + goto error; + } + + attest_err = attest_add_all_sw_components(&attest_token_ctx); + if (attest_err != PSA_ATTEST_ERR_SUCCESS) { + goto error; + } + } + + /* Finish up creating the token. This is where the actual signature + * is generated. This finishes up the CBOR encoding too. + */ + token_err = attest_token_finish(&attest_token_ctx, completed_token); + if (token_err) { + attest_err = error_mapping(token_err); + goto error; + } + +error: + return attest_err; +} + +/* Limitations of the current implementation: + * - Token is not signed yet properly, just a fake signature is added to the + * token due to lack of psa_sign_hash() implementation in crypto + * service. + */ +enum psa_attest_err_t +initial_attest_get_token(const psa_invec *in_vec, uint32_t num_invec, + psa_outvec *out_vec, uint32_t num_outvec) +{ + enum psa_attest_err_t attest_err = PSA_ATTEST_ERR_SUCCESS; + struct useful_buf_c challenge; + struct useful_buf token; + struct useful_buf_c completed_token; + + challenge.ptr = in_vec[0].base; + challenge.len = in_vec[0].len; + token.ptr = out_vec[0].base; + token.len = out_vec[0].len; + + attest_err = attest_verify_challenge_size(challenge.len); + if (attest_err != PSA_ATTEST_ERR_SUCCESS) { + goto error; + } + + attest_err = attest_check_memory_access((void *)challenge.ptr, + challenge.len, + TFM_ATTEST_ACCESS_RO); + if (attest_err != PSA_ATTEST_ERR_SUCCESS) { + goto error; + } + + attest_err = attest_check_memory_access(token.ptr, + token.len, + TFM_ATTEST_ACCESS_RW); + if (attest_err != PSA_ATTEST_ERR_SUCCESS) { + goto error; + } + + attest_err = attest_create_token(&challenge, &token, &completed_token); + if (attest_err != PSA_ATTEST_ERR_SUCCESS) { + goto error; + } + + out_vec[0].base = (void *)completed_token.ptr; + out_vec[0].len = completed_token.len; + +error: + return attest_err; +} + +/* Initial implementation, just returns with hard coded value */ +enum psa_attest_err_t +initial_attest_get_token_size(const psa_invec *in_vec, uint32_t num_invec, + psa_outvec *out_vec, uint32_t num_outvec) +{ + enum psa_attest_err_t attest_err = PSA_ATTEST_ERR_SUCCESS; + uint32_t challenge_size = *(uint32_t *)in_vec[0].base; + uint32_t *token_buf_size = (uint32_t *)out_vec[0].base; + struct useful_buf_c challenge; + struct useful_buf token; + struct useful_buf_c completed_token; + + /* Only the size of the challenge is needed */ + challenge.ptr = NULL; + challenge.len = challenge_size; + + /* Special value to get the size of the token, but token is not created */ + token.ptr = NULL; + token.len = INT32_MAX; + + if (out_vec[0].len < sizeof(uint32_t)) { + attest_err = PSA_ATTEST_ERR_INVALID_INPUT; + goto error; + } + + attest_err = attest_verify_challenge_size(challenge_size); + if (attest_err != PSA_ATTEST_ERR_SUCCESS) { + goto error; + } + + attest_err = attest_create_token(&challenge, &token, &completed_token); + if (attest_err != PSA_ATTEST_ERR_SUCCESS) { + goto error; + } + + *token_buf_size = completed_token.len; + +error: + return attest_err; +} diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/t_cose/CMakeLists.txt b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/t_cose/CMakeLists.txt new file mode 100644 index 0000000..e1f1985 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/t_cose/CMakeLists.txt @@ -0,0 +1,40 @@ +#------------------------------------------------------------------------------- +# Copyright (c) 2019, Arm Limited. All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# +#------------------------------------------------------------------------------- + +cmake_minimum_required(VERSION 3.7) + +#Tell cmake where our modules can be found +list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/../../../cmake) + +#Include common stuff to control cmake. +include("Common/BuildSys") + +#Start an embedded project. +embedded_project_start(CONFIG "${CMAKE_CURRENT_LIST_DIR}/../../ConfigDefault.cmake") +project(tfm_t_cose LANGUAGES C) +embedded_project_fixup() + +#Some project global settings +set(T_COSE_DIR "${CMAKE_CURRENT_LIST_DIR}") + +#Append all our source files to global lists. +list(APPEND ALL_SRC_C + "${T_COSE_DIR}/src/t_cose_sign1_sign.c" + "${T_COSE_DIR}/src/t_cose_util.c" + "${T_COSE_DIR}/src/t_cose_psa_crypto.c" + ) + +#Setting include directories +embedded_include_directories(PATH ${T_COSE_DIR}/inc ABSOLUTE) + +#Specify what we build (for the t_cose, build as an object library) +add_library(${PROJECT_NAME} OBJECT ${ALL_SRC_C}) + +#Set common compiler flags +config_setting_shared_compiler_flags(${PROJECT_NAME}) + +embedded_project_end(${PROJECT_NAME}) diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/t_cose/README.md b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/t_cose/README.md new file mode 100644 index 0000000..9501806 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/t_cose/README.md @@ -0,0 +1,95 @@ +# t_cose + +## Introduction + +t_cose is a partial implementation of the COSE standard (RFC 8152). +COSE is quite a large standard so a full implementation of all of it +is a large undertaking. This implementation is starting out as just +enough for attestation and maybe CWT (Cbor Web Token) which is very +similar. + +As it may grow to support more of COSE over time, it is structured +with that in mind. + +It is also trying to be portable, the most interesting part of which +is interfacing with the libraries for performing cryptography and +access cryptographic keys. + +## Source files +The following files are more or less the public interface. +* t_cose_common.h +* t_cose_sign1.h +* t_cose_sign1_verify.h + +The rest of the files are internal source files that callers should +not depend on. + +t_cose_defines.h contains contants from RFC 8152 that are +part of the COSE standard. It should never have anything else +in it. + +t_cose_util is some utilities and code common to +signing and verification. Both signing and verifcation +depend on it. + +t_cose_crypto is the crypto porting layer. Generally +the .h file should not need to change for a new +platform. The .c file will be changed lots for +each new platform. + +## Dependency and Portability +t_cose is attempting to be very portable and +have a minmum number of #ifdefs. It is +designed to run 64-bit and 32-bit machines. + +It uses a minimum number of standard C +libraries, mostly just , and . + +It uses QCBOR for CBOR encoding and decoding. +QCBOR is very portable. + +### Cryptography and Keys +There is a cryptographic adaption layer that +provides the following: +* Impedence match of parameters passed to/from the crypto +* Management of algorithm identifiers +* Management of error codes +* Management of key identifiers + +It is framed for the needs of t_cose, and is +not trying to be any kind of general crypto API. + +#### Question +Q: How many crypto APIs does it take to screw in a light bulb? +A: One more than it takes to screw in a light bulb. + +## Copyright and License + +### BSD-3-Clause license + +* Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +### Copyright for this README + +Copyright (c) 2018-2019, Laurence Lundblade. All rights reserved. diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/t_cose/inc/t_cose_common.h b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/t_cose/inc/t_cose_common.h new file mode 100644 index 0000000..d509a4b --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/t_cose/inc/t_cose_common.h @@ -0,0 +1,148 @@ +/* + * t_cose_common.h + * + * Copyright 2019, Laurence Lundblade + * + * SPDX-License-Identifier: BSD-3-Clause + * + * See BSD-3-Clause license in README.mdE. + */ + + +#ifndef __T_COSE_COMMON_H__ +#define __T_COSE_COMMON_H__ + + +/** + * \file t_cose_common.h + * + * \brief Defines common to all public t_cose interfaces. + * + */ + + +/* Private value. Intentionally not documented for Doxygen. + * This is the size allocated for the encoded protected headers. It + * needs to be big enough for make_protected_header() to succeed. It + * currently sized for one header with an algorithm ID up to 32 bits + * long -- one byte for the wrapping map, one byte for the label, 5 + * bytes for the ID. If this is made accidentially too small, QCBOR will + * only return an error, and not overrun any buffers. + * + * 9 extra bytes are added, rounding it up to 16 total, in case some + * other protected header is to be added. + */ +#define T_COSE_SIGN1_MAX_PROT_HEADER (1+1+5+9) + + +/** + * Error codes return by t_cose. + * + * Do not reorder these. It is OK to add + * new ones at the end. + */ +enum t_cose_err_t { + /** + * Operation completed successfully + */ + T_COSE_SUCCESS = 0, + /** + * The requested signing algorithm is not supported. + */ + T_COSE_ERR_UNSUPPORTED_SIGNING_ALG, + /** + * Error constructing the protected headers. + */ + T_COSE_ERR_PROTECTED_HEADERS, + /** + * The hash algorithm needed is not supported. Note that the + * signing algorithm identifier usually identifies the hash + * algorithm. + */ + T_COSE_ERR_UNSUPPORTED_HASH, + /** + * Some system failure when running the hash algorithm. + */ + T_COSE_ERR_HASH_GENERAL_FAIL, + /** + * The buffer to receive a hash result is too small. + */ + T_COSE_ERR_HASH_BUFFER_SIZE, + /** + * The buffer to receive result of a signing operation is too + * small. + */ + T_COSE_ERR_SIG_BUFFER_SIZE, + /** + * The buffer to receive to receive a key is too small. + */ + T_COSE_ERR_KEY_BUFFER_SIZE, + /** + * When verifying a \c COSE_Sign1, something is wrong with the + * format of the CBOR. For example, it is missing something like + * the payload. + */ + T_COSE_ERR_SIGN1_FORMAT, + /** + * When decoding some CBOR like a \c COSE_Sign1, the CBOR was not + * well-formed. Most likely what was supposed to be CBOR was is + * either not or it has been corrupted. + */ + T_COSE_ERR_CBOR_NOT_WELL_FORMED, + /** + * No algorithm ID was found when one is needed. For example, when + * verifying a \c COSE_Sign1. + */ + T_COSE_ERR_NO_ALG_ID, + /** + * No key ID was found when one is needed. For example, when + * verifying a \c COSE_Sign1. + */ + T_COSE_ERR_NO_KID, + /** + * Signature verification failed. For example, the cryptographic + * operations completed successfully but hash wasn't as expected. + */ + T_COSE_ERR_SIG_VERIFY, + /** + * Verification of a short-circuit signature failed. + */ + T_COSE_ERR_BAD_SHORT_CIRCUIT_KID, + /** + * Some (unspecified) argument was not valid. + */ + T_COSE_ERR_INVALID_ARGUMENT, + /** + * Out of heap memory. + */ + T_COSE_ERR_INSUFFICIENT_MEMORY, + /** + * General unspecific failure. + */ + T_COSE_ERR_FAIL, + /** + * Equivalent to \c PSA_ERROR_TAMPERING_DETECTED. + */ + T_COSE_ERR_TAMPERING_DETECTED, + /** + * The key identified by a key slot of a key ID was not found. + */ + T_COSE_ERR_UNKNOWN_KEY, + /** + * The key was found, but it was the wrong type for the operation. + */ + T_COSE_ERR_WRONG_TYPE_OF_KEY, + /** + * Error constructing the \c Sig_structure when signing or verify. + */ + T_COSE_ERR_SIG_STRUCT, + /** + * Signature was short-circuit. THe option to allow verification + * of short-circuit signatures was not set + */ + T_COSE_ERR_SHORT_CIRCUIT_SIG +}; + + + +#endif /* __T_COSE_COMMON_H__ */ diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/t_cose/inc/t_cose_sign1_sign.h b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/t_cose/inc/t_cose_sign1_sign.h new file mode 100644 index 0000000..35b26e5 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/t_cose/inc/t_cose_sign1_sign.h @@ -0,0 +1,181 @@ +/* + * t_cose_sign1_sign.h + * + * Copyright (c) 2018-2019, Laurence Lundblade. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + * See BSD-3-Clause license in README.md + */ + +#ifndef __T_COSE_SIGN1_H__ +#define __T_COSE_SIGN1_H__ + +#include +#include +#include "qcbor.h" +#include "t_cose_common.h" + + +/** + * \file t_cose_sign1_sign.h + * + * \brief Create a \c COSE_Sign1, usually for EAT or CWT Token. + * + * This creates a \c COSE_Sign1 in compliance with [COSE (RFC 8152)] + * (https://tools.ietf.org/html/rfc8152). A \c COSE_Sign1 is a CBOR + * encoded binary blob that contains headers, a payload and a + * signature. Usually the signature is made with an EC signing + * algorithm like ECDSA. + * + * This implementation is intended to be small and portable to + * different OS's and platforms. Its dependencies are: + * - QCBOR + * - , , + * - Hash functions like SHA-256 + * - Signing functions like ECDSA + * + * There is a cryptographic adaptation layer defined in + * t_cose_crypto.h. An implementation can be made of the functions in + * it for different platforms or OS's. This means that different + * platforms and OS's may support only signing with a particular set + * of algorithms. + * + * This \c COSE_Sign1 implementations is optimized for creating EAT + * tokens. + * + * It should work for CWT and others use cases too. The main point of + * the optimization is that only one output buffer is needed. There is + * no need for one buffer to hold the payload and another to hold the + * end result \c COSE_Sign1. The payload is encoded right into its final + * place in the end result \c COSE_Sign1. + */ + + +/** + * This is the context for creating a \c COSE_Sign1 structure. The caller + * should allocate it and pass it to the functions here. This is + * about 32 bytes so it fits easily on the stack. + */ +struct t_cose_sign1_ctx { + /* Private data structure */ + uint8_t buffer_for_protected_headers[ + T_COSE_SIGN1_MAX_PROT_HEADER]; + struct useful_buf_c protected_headers; + int32_t cose_algorithm_id; + int32_t key_select; + bool short_circuit_sign; + QCBOREncodeContext *cbor_encode_ctx; +}; + + +/** + * \brief Initialize to start creating a \c COSE_Sign1. + * + * \param[in] me The t_cose signing context. + * \param[in] short_circuit_sign \c true to select special test mode. + * \param[in] cose_algorithm_id The algorithm to sign with. The IDs are + * defined in [COSE (RFC 8152)] + * (https://tools.ietf.org/html/rfc8152) or + * in the [IANA COSE Registry] + * (https://www.iana.org/assignments/cose/cose.xhtml). + * \param[in] key_select Which signing key to use. + * \param[in] cbor_encode_ctx The CBOR encoder context to output to. + * + * \return This returns one of the error codes defined by \ref t_cose_err_t. + * + * It is possible to use this to compute the exact size of the + * resulting token so the exact sized buffer can be allocated. To do + * this initialize the \c cbor_encode_ctx with \c UsefulBufC that has + * a \c NULL pointer and large length like \c UINT32_MAX. Then run the + * normal token creation. The result will have a NULL pointer and the + * length of the token that would have been created. When this is run + * like this, the cryptographic functions will not actually run, but + * the size of their output will be taken into account. + * + * The key selection depends on the platform / OS. + * + * Which signing algorithms are supported depends on the platform/OS. + * The header file t_cose_defines.h contains defined constants for + * some of them. A typical example is \ref COSE_ALGORITHM_ES256 which + * indicates ECDSA with the NIST P-256 curve and SHA-256. + * + * To use this, create a \c QCBOREncodeContext and initialize it with + * an output buffer big enough to hold the payload and the COSE Sign 1 + * overhead. This overhead is about 30 bytes plus the size of the + * signature and the size of the key ID. + * + * After the \c QCBOREncodeContext is initialized, call + * t_cose_sign1_init() on it. + * + * Next call \c QCBOREncode_BstrWrap() to indicate the start of the + * payload. + * + * Next call various \c QCBOREncode_Addxxxx() methods to create the + * payload. + * + * Next call \c QCBOREncode_CloseBstrWrap() to indicate the end of the + * payload. This will also return a pointer and length of the payload + * that gets hashed. + * + * Next call t_cose_sign1_finish() with the pointer and length of the + * payload. This will do all the cryptography and complete the COSE + * Sign1. + * + * Finally, call \c QCBOREncode_Finish() to get the pointer and length + * of the complete token. + * + * This implements a special signing test mode called _short_ + * _circuit_ _signing_. This mode is useful when there is no signing + * key available, perhaps because it has not been provisioned or + * configured for the particular device. It may also be because the + * public key cryptographic functions have not been connected up in + * the cryptographic adaptation layer. + * + * It has no value for security at all. Data signed this way should + * not be trusted as anyone can sign like this. + * + * In this mode the signature is the hash of that would normally be + * signed by the public key algorithm. To make the signature the + * correct size for the particular algorithm instances of the hash are + * concatenated to pad it out. + * + * This mode is very useful for testing because all the code except + * the actual signing algorithm is run exactly as it would if a proper + * signing algorithm was run. + * + * The kid (Key ID) put in the unprotected headers is created as + * follows. The EC public key is CBOR encoded as a \c COSE_Key as + * defined in the COSE standard. That encoded CBOR is then + * hashed with SHA-256. This is similar to key IDs defined in IETF + * PKIX, but is based on COSE and CBOR rather than ASN.1. + */ +enum t_cose_err_t t_cose_sign1_init(struct t_cose_sign1_ctx *me, + bool short_circuit_sign, + int32_t cose_algorithm_id, + int32_t key_select, + QCBOREncodeContext *cbor_encode_ctx); + + +/** + * \brief Finish creation of the \c COSE_Sign1. + * + * \param[in] me The t_cose signing context. + * \param[in] payload The pointer and length of the payload. + * + * \return This returns one of the error codes defined by \ref t_cose_err_t. + * + * Call this to complete creation of a signed token started with + * t_cose_sign1_init(). + * + * This is when the signature algorithm is run. + * + * The payload parameter is used only to compute the hash for + * signing. The completed \c COSE_Sign1 is retrieved from the \c + * cbor_encode_ctx by calling \c QCBOREncode_Finish() + */ +enum t_cose_err_t t_cose_sign1_finish(struct t_cose_sign1_ctx *me, + struct useful_buf_c payload); + + +#endif /* __T_COSE_SIGN1_H__ */ diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/t_cose/src/t_cose_crypto.h b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/t_cose/src/t_cose_crypto.h new file mode 100644 index 0000000..ab4faac --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/t_cose/src/t_cose_crypto.h @@ -0,0 +1,413 @@ +/* + * t_cose_crypto.h + * + * Copyright 2019, Laurence Lundblade + * + * SPDX-License-Identifier: BSD-3-Clause + * + * See BSD-3-Clause license in README.mdE. + */ + + +#ifndef __T_COSE_CRYPTO_H__ +#define __T_COSE_CRYPTO_H__ + +#include "t_cose_common.h" +#include "useful_buf.h" +#include +#include "t_cose_defines.h" + + +/** + * \file t_cose_crypto.h + * + * \brief This is the adaptation layer for cryptographic functions used by + * t_cose. + * + * This is small wrapper around the cryptographic functions to: + * - Map COSE algorithm IDs to TF-M algorithm IDs + * - Map crypto errors to \ref t_cose_err_t errors + * - Have inputs and outputs be \c struct \c useful_buf_c and + * \c struct \c useful_buf + * - Handle key selection + * + * The idea is that implementations can be made of these functions + * that adapt to various cryptographic libraries that are used on + * various platforms and OSs. + * + * This runs entirely off of COSE-style algorithm identifiers. They + * are simple integers and thus work nice as function parameters. An + * initial set is defined by [COSE (RFC 8152)] + * (https://tools.ietf.org/html/rfc8152). New ones can be registered + * in the [IANA COSE Registry] + * (https://www.iana.org/assignments/cose/cose.xhtml). Local use new + * ones can also be defined (\c \#define) if what is needed is not in + * the IANA registry. + * + * Binary data is returned to the caller using a \c struct \c + * useful_buf to pass the buffer to receive the data and its length in + * and a \c useful_buf_c to return the pointer and length of the + * returned data. The point of this is coding hygiene. The buffer + * passed in is not const as it is to be modified. The \c + * useful_buf_c returned is const. + * + * The pointer in the \c useful_buf_c will always point to the buffer + * passed in via the \c useful_buf so the lifetime of the data is + * under control of the caller. + * + * This is not intended as any sort of general cryptographic API. It + * is just the functions needed by t_cose in the form that is most + * useful for t_cose. + */ + + +/** + * Size of the signature output for the NIST P-256 Curve. + */ +#define T_COSE_EC_P256_SIG_SIZE 64 + +/** + * Size of the largest signature of any of the algorithm types + * supported. + * + * This will have to be adjusted if support for other algorithms + * larger is added. + * + * This is a compile time constant so it can be used to define stack + * variable sizes. + */ +#define T_COSE_MAX_EC_SIG_SIZE T_COSE_EC_P256_SIG_SIZE + + +/** + * \brief Get the size in bytes of a particular signature type. + * + * \param[in] cose_sig_alg_id The COSE algorithm ID. + * + * \return The size in bytes of the signature for a public-key signing + * algorithm. + */ +static inline size_t t_cose_signature_size(int32_t cose_sig_alg_id); + + +/** + * \brief Perform public key signing. Part of the t_cose crypto + * adaptation layer. + * + * \param[in] cose_alg_id The algorithm to sign with. The IDs are + * defined in [COSE (RFC 8152)] + * (https://tools.ietf.org/html/rfc8152) or + * in the [IANA COSE Registry] + * (https://www.iana.org/assignments/cose/cose.xhtml). + * A proprietary ID can also be defined + * locally (\c \#define) if the needed + * one hasn't been registered. + * \param[in] key_select Indicates which key to use to sign. + * \param[in] hash_to_sign The bytes to sign. Typically, a hash of + * a payload. + * \param[in] signature_buffer Pointer and length of buffer into which + * the resulting signature is put. + * \param[in] signature Pointer and length of the signature + * returned. + * + * \retval T_COSE_SUCCESS + * Successfully created the signature. + * \retval T_COSE_ERR_SIG_BUFFER_SIZE + * The \c signature_buffer too small. + * \retval T_COSE_ERR_UNSUPPORTED_SIGNING_ALG + * The requested signing algorithm, \c cose_alg_id, is not + * supported. + * \retval T_COSE_ERR_UNKNOWN_KEY + * The key identified by \c key_select was not found. + * \retval T_COSE_ERR_WRONG_TYPE_OF_KEY + * The key was found, but it was the wrong type. + * \retval T_COSE_ERR_INVALID_ARGUMENT + * Some (unspecified) argument was not valid. + * \retval T_COSE_ERR_INSUFFICIENT_MEMORY + * Insufficient heap memory. + * \retval T_COSE_ERR_FAIL + * General unspecific failure. + * \retval T_COSE_ERR_TAMPERING_DETECTED + * Equivalent to \c PSA_ERROR_TAMPERING_DETECTED. + * + * This is called to do public key signing. The implementation will + * vary from one platform / OS to another but should conform to the + * description here. + * + * The key selection depends on the platform / OS. + * + * See the note in the Detailed Description (the \\file comment block) + * for details on how \c useful_buf and \c useful_buf_c are used to + * return the signature. + * + * To find out the size of the signature buffer needed, call this with + * \c signature_buffer->ptr \c NULL and \c signature_buffer->len a + * very large number like \c UINT32_MAX. The size will be returned in + * \c signature->len. + */ +enum t_cose_err_t +t_cose_crypto_pub_key_sign(int32_t cose_alg_id, + int32_t key_select, + struct useful_buf_c hash_to_sign, + struct useful_buf signature_buffer, + struct useful_buf_c *signature); + + +/** + * \brief perform public key signature verification. Part of the + * t_cose crypto adaptation layer. + * + * \param[in] cose_alg_id The algorithm to use for verification. + * The IDs are defined in [COSE (RFC 8152)] + * (https://tools.ietf.org/html/rfc8152) + * or in the [IANA COSE Registry] + * (https://www.iana.org/assignments/cose/cose.xhtml). + * A proprietary ID can also be defined + * locally (\c \#define) if the needed one + * hasn't been registered. + * \param[in] key_select Verification key selection. + * \param[in] key_id A key id or \c NULL_USEFUL_BUF_C. + * \param[in] hash_to_verify The data or hash that is to be verified. + * \param[in] signature The signature. + * + * This verifies that the \c signature passed in was over the \c + * hash_to_verify passed in. + * + * The public key used to verify the signature is selected by the \c + * key_id if it is not \c NULL_USEFUL_BUF_C or the \c key_select if it + * is. + * + * The key selected must be, or include, a public key of the correct + * type for \c cose_alg_id. + * + * \retval T_COSE_SUCCESS + * The signature is valid + * \retval T_COSE_ERR_SIG_VERIFY + * Signature verification failed. For example, the + * cryptographic operations completed successfully but hash + * wasn't as expected. + * \retval T_COSE_ERR_UNKNOWN_KEY + * The key identified by \c key_select or a \c kid was + * not found. + * \retval T_COSE_ERR_WRONG_TYPE_OF_KEY + * The key was found, but it was the wrong type + * for the operation. + * \retval T_COSE_ERR_UNSUPPORTED_SIGNING_ALG + * The requested signing algorithm is not supported. + * \retval T_COSE_ERR_INVALID_ARGUMENT + * Some (unspecified) argument was not valid. + * \retval T_COSE_ERR_INSUFFICIENT_MEMORY + * Out of heap memory. + * \retval T_COSE_ERR_FAIL + * General unspecific failure. + * \retval T_COSE_ERR_TAMPERING_DETECTED + * Equivalent to \c PSA_ERROR_TAMPERING_DETECTED. + */ +enum t_cose_err_t +t_cose_crypto_pub_key_verify(int32_t cose_alg_id, + int32_t key_select, + struct useful_buf_c key_id, + struct useful_buf_c hash_to_verify, + struct useful_buf_c signature); + + +/** + * The size of X and Y coordinate in 2 parameter style EC public + * key. Format is as defined in [COSE (RFC 8152)] + * (https://tools.ietf.org/html/rfc8152) and [SEC 1: Elliptic Curve + * Cryptography](http://www.secg.org/sec1-v2.pdf). + * + * This size is well-known and documented in public standards. + */ +#define T_COSE_CRYPTO_EC_P256_COORD_SIZE 32 + + +/** + * \brief Get an elliptic curve public key. Part of the t_cose crypto + * adaptation layer. + * + * \param[in] key_select Used to look up the public + * key to return when \c kid is + * \c NULL_USEFUL_BUF_C. + * \param[in] kid A key ID to look up against. May be + * \c NULL_USEFUL_BUF_C. This is typically + * the kid from the COSE unprotected header. + * \param[out] cose_curve_id The curve ID of the key returned as + * defined by [COSE (RFC 8152)] + * (https://tools.ietf.org/html/rfc8152) + * or the IANA COSE registry. + * \param[in] buf_to_hold_x_coord Pointer and length into which the + * X coordinate is put. + * \param[in] buf_to_hold_y_coord Pointer and length into which the + * Y coordinate is put. + * \param[out] x_coord Pointer and length of the returned X + * coordinate. + * \param[out] y_coord Pointer and length of the returned Y + * coordinate. + * + * \retval T_COSE_SUCCESS + * The key was found and is returned. + * \retval T_COSE_ERR_UNKNOWN_KEY + * The key identified by \c key_select or a \c kid was not + * found. + * \retval T_COSE_ERR_WRONG_TYPE_OF_KEY + * The key was found, but it was the wrong type for the + * operation. + * \retval T_COSE_ERR_FAIL + * General unspecific failure. + * \retval T_COSE_ERR_KEY_BUFFER_SIZE + * Buffer to hold the output was too small. + * + * This finds and returns a public key. Where it looks for the key is + * dependent on the OS / platform. + * + * \ref T_COSE_CRYPTO_EC_P256_COORD_SIZE is the size of the X or Y + * coordinate for the NIST P-256 curve. + * + * See the note in the Detailed Description (the \\file comment block) + * for details on how \c useful_buf and \c useful_buf_c are used to + * return the X and Y coordinates. + */ +enum t_cose_err_t +t_cose_crypto_get_ec_pub_key(int32_t key_select, + struct useful_buf_c kid, + int32_t *cose_curve_id, + struct useful_buf buf_to_hold_x_coord, + struct useful_buf buf_to_hold_y_coord, + struct useful_buf_c *x_coord, + struct useful_buf_c *y_coord); + + +/* + * No function to get private key because there is no need for it. + * The private signing key only needs to exist behind + * t_cose_crypto_pub_key_sign(). + */ + + + + +/** + * The context for use with the hash adaptation layer here. + */ +struct t_cose_crypto_hash { + /* Can't put the actual size here without creating dependecy on + * actual hash implementation, so this is a fairly large and + * accommodating size. + */ + uint8_t bytes[280]; +}; + + +/** + * The size of the output of SHA-256 in bytes. + * + * (It is safe to define this independently here as its size is + * well-known and fixed. There is no need to reference + * platform-specific headers and incur messy dependence.) + */ +#define T_COSE_CRYPTO_SHA256_SIZE 32 + + +/** + * \brief Start cryptographic hash. Part of the t_cose crypto + * adaptation layer. + * + * \param[in,out] hash_ctx Pointer to the hash context that + * will be initialized. + * \param[in] cose_hash_alg_id Algorithm ID that identifies the + * hash to use. This is from the + * [IANA COSE Registry] + * (https://www.iana.org/assignments/cose/cose.xhtml). + * As of the creation of this interface + * no identifiers of only a hash + * functions have been registered. + * Signature algorithms that include + * specification of the hash have been + * registered, but they are not to be + * used here. Until hash functions only + * have been officially registered, some + * IDs are defined in the proprietary + * space in t_cose_common.h. + * + * \retval T_COSE_ERR_UNSUPPORTED_HASH + * The requested algorithm is unknown or unsupported. + * + * \retval T_COSE_ERR_HASH_GENERAL_FAIL + * Some general failure of the hash function + * + * This initializes the hash context for the particular algorithm. It + * must be called first. A \c hash_ctx can be reused if it is + * reinitialized. + */ +enum t_cose_err_t +t_cose_crypto_hash_start(struct t_cose_crypto_hash *hash_ctx, + int32_t cose_hash_alg_id); + + +/** + * \brief Feed data into a cryptographic hash. Part of the t_cose + * crypto adaptation layer. + * + * \param[in,out] hash_ctx Pointer to the hash context in which + * accumulate the hash. + * \param[in] data_to_hash Pointer and length of data to feed into + * hash. The pointer may by \c NULL in which + * case no hashing is performed. + * + * There is no return value. If an error occurs it is remembered in \c + * hash_ctx and returned when t_cose_crypto_hash_finish() is called. + * Once in the error state, this function may be called, but it will + * not do anything. + */ +void t_cose_crypto_hash_update(struct t_cose_crypto_hash *hash_ctx, + struct useful_buf_c data_to_hash); + + +/** + * \brief Finish a cryptographic hash. Part of the t_cose crypto + * adaptation layer. + * + * \param[in,out] hash_ctx Pointer to the hash context. + * \param[in] buffer_to_hold_result Pointer and length into which + * the resulting hash is put. + * \param[out] hash_result Pointer and length of the + * resulting hash. + * + * \retval T_COSE_ERR_HASH_GENERAL_FAIL + * Some general failure of the hash function. + * \retval T_COSE_ERR_HASH_BUFFER_SIZE + * The size of the buffer to hold the hash result was + * too small. + * + * Call this to complete the hashing operation. If the everything + * completed correctly, the resulting hash is returned. Note that any + * errors that occurred during t_cose_crypto_hash_update() are + * returned here. + * + * See the note in the Detailed Description (the \\file comment block) + * for details on how \c useful_buf and \c useful_buf_c are used to + * return the hash. + */ +enum t_cose_err_t +t_cose_crypto_hash_finish(struct t_cose_crypto_hash *hash_ctx, + struct useful_buf buffer_to_hold_result, + struct useful_buf_c *hash_result); + + + +/* + * Public inline function. See documentation above. + */ +static inline size_t t_cose_signature_size(int32_t cose_sig_alg_id) +{ + switch(cose_sig_alg_id) { + case COSE_ALGORITHM_ES256: + return T_COSE_EC_P256_SIG_SIZE; + default: + return T_COSE_EC_P256_SIG_SIZE; + } +} + + +#endif /* __T_COSE_CRYPTO_H__ */ diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/t_cose/src/t_cose_defines.h b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/t_cose/src/t_cose_defines.h new file mode 100644 index 0000000..e2cc970 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/t_cose/src/t_cose_defines.h @@ -0,0 +1,291 @@ +/* + * t_cose_defines.h + * + * Copyright (c) 2018-2019, Laurence Lundblade. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + * See BSD-3-Clause license in README.md + */ + +#ifndef __T_COSE_DEFINES_H__ +#define __T_COSE_DEFINES_H__ + +/** + * \file t_cose_defines.h + * + * \brief Constants from COSE standard and IANA registry. + * + * This file contains constants identifiers defined in [COSE (RFC + * 8152)] (https://tools.ietf.org/html/rfc8152) and [IANA COSE + * Registry] (https://www.iana.org/assignments/cose/cose.xhtml). They + * include algorithm IDs and other constants. + * + * Many constants in the IANA registry are not included here yet as + * they are not needed by t_cose. They can be added if they become + * needed. + */ + + + + +/* --------------- COSE Header parameters ----------- + * https://www.iana.org/assignments/cose/cose.xhtml#header-parameters + */ + +/** + * \def COSE_HEADER_PARAM_ALG + * + * \brief Label of COSE header that indicates an algorithm. + */ +#define COSE_HEADER_PARAM_ALG 1 + +/** + * \def COSE_HEADER_PARAM_KID + * + * \brief Label of COSE header that contains a key ID. + */ +#define COSE_HEADER_PARAM_KID 4 + + + + +/* ------------ COSE Header Algorithm Parameters -------------- + * https://www.iana.org/assignments/cose/cose.xhtml#header-algorithm-parameters + * + * None of these are defined here yet, as they are not needed by t_cose yet. + */ + + + + +/* ------------- COSE Algorithms ---------------------------- + * https://www.iana.org/assignments/cose/cose.xhtml#algorithms + */ + +/** + * \def COSE_ALGORITHM_ES256 + * + * \brief Indicates ECDSA with SHA-256. + * + * Value for \ref COSE_HEADER_PARAM_ALG to indicate ECDSA. w/SHA-256 + */ +#define COSE_ALGORITHM_ES256 -7 + +/** + * \def COSE_ALGORITHM_ES384 + * + * \brief Indicates ECDSA with SHA-384. + * + * Value for \ref COSE_HEADER_PARAM_ALG to indicate ECDSA. w/SHA-384 + */ +#define COSE_ALGORITHM_ES384 -35 + +/** + * \def COSE_ALGORITHM_ES512 + * + * \brief Indicates ECDSA with SHA-384. + * + * Value for \ref COSE_HEADER_PARAM_ALG to indicate ECDSA. w/SHA-512 + */ +#define COSE_ALGORITHM_ES512 -36 + + +/** + * \def COSE_ALG_SHA256_PROPRIETARY + * + * \brief COSE-style algorithm ID for SHA256. The official COSE + * algorithm registry doesn't yet define an ID for a pure hash + * function. One is needed for internal use, so this is defined. + * + * This is only used internally in the implementation and doesn't + * appear in any protocol messages so there are no interoperability + * issues. When this gets defined in the IANA registry, that value can + * be substituted here and all will work fine. + */ +#define COSE_ALG_SHA256_PROPRIETARY -72000 + + + + +/* ---------- COSE Key Common Parameters -------------- + * https://www.iana.org/assignments/cose/cose.xhtml#key-common-parameters + */ + +/** + * \def COSE_KEY_COMMON_KTY + * + * \brief Label for data item containing the key type. + * + * In a \c COSE_Key, label that indicates the data item containing the + * key type. + */ +#define COSE_KEY_COMMON_KTY 1 + +/** + * \def COSE_KEY_COMMON_KID + * + * \brief Label for data item containing the key's kid. + * + * In a \c COSE_Key, label that indicates the data item containing the + * kid of this key. + */ +#define COSE_KEY_COMMON_KID 2 + + + + +/* ---------- COSE Key Type Parameters -------------------- + * https://www.iana.org/assignments/cose/cose.xhtml#key-type-parameters + */ + +/** + * \def COSE_KEY_PARAM_CRV + * + * \brief Label for data item indicating EC curve. + * + * In a \c COSE_Key that holds an EC key of either type \ref + * COSE_KEY_TYPE_EC2 or \ref COSE_KEY_TYPE_OKP this labels the data + * item with the EC curve for the key. + */ +#define COSE_KEY_PARAM_CRV -1 + +/** + * \def COSE_KEY_PARAM_X_COORDINATE + * + * \brief Label for data item that is an X coordinate of an EC key. + * + * In a \c COSE_Key that holds an EC key, this is label that indicates + * the data item containing the X coordinate. + * + * This is used for both key types \ref COSE_KEY_TYPE_EC2 and \ref + * COSE_KEY_TYPE_OKP. + */ +#define COSE_KEY_PARAM_X_COORDINATE -2 + +/** + * \def COSE_KEY_PARAM_Y_COORDINATE + * + * \brief Label for data item that is a y coordinate of an EC key. + * + * In a COSE_Key that holds an EC key, this is label that indicates + * the data item containing the Y coordinate. + * + * This is used only for key type \ref COSE_KEY_TYPE_EC2. + */ +#define COSE_KEY_PARAM_Y_COORDINATE -3 + +/** + * \def COSE_KEY_PARAM_PRIVATE_D + * + * \brief Label for data item that is d, the private part of EC key. + * + * In a \c COSE_Key that holds an EC key, this is label that indicates + * the data item containing the Y coordinate. + * + * This is used for both key types \ref COSE_KEY_TYPE_EC2 and \ref + * COSE_KEY_TYPE_OKP. + */ +#define COSE_KEY_PARAM_PRIVATE_D -4 + + + + +/* ---------- COSE Key Types -------------------------------- + * https://www.iana.org/assignments/cose/cose.xhtml#key-type + */ + +/** + * \def COSE_KEY_TYPE_OKP + * + * \brief Key type is Octet Key Pair + * + * In a \c COSE_Key, this is a value of the data item labeled \ref + * COSE_KEY_COMMON_KTY that indicates the \c COSE_Key is some sort of + * key pair represented by some octets. It may or may not be an EC + * key. + */ +#define COSE_KEY_TYPE_OKP 1 + +/** + * \def COSE_KEY_TYPE_EC2 + * + * \brief Key is a 2-parameter EC key. + * + * In a \c COSE_Key, this is a value of the data item labeled \ref + * COSE_KEY_COMMON_KTY that indicates the \c COSE_Key is an EC key + * specified with two coordinates, X and Y. + */ +#define COSE_KEY_TYPE_EC2 2 + +/** + * \def COSE_KEY_TYPE_SYMMETRIC + * + * \brief Key is a symmetric key. + * + * In a \c COSE_Key, this is a value of the data item labeled \ref + * COSE_KEY_COMMON_KTY that indicates the \c COSE_Key is a symmetric + * key. + */ +#define COSE_KEY_TYPE_SYMMETRIC 4 + + + + +/* ----------- COSE Elliptic Curves --------------------- + * https://www.iana.org/assignments/cose/cose.xhtml#elliptic-curves + */ + +/** + * \def COSE_ELLIPTIC_CURVE_P_256 + * + * \brief Key type for NIST P-256 key + * + * In a \c COSE_Key, this is a value of the data item labeled \ref + * COSE_KEY_PARAM_CRV to indicate the NIST P-256 curve, also known as + * secp256r1. + * + * This key type is always \ref COSE_KEY_TYPE_EC2. + */ +#define COSE_ELLIPTIC_CURVE_P_256 1 + +/** + * \def COSE_ELLIPTIC_CURVE_P_384 + * + * \brief Key type for NIST P-384 key + * + * In a \c COSE_Key, this is a value of the data item labeled \ref + * COSE_KEY_PARAM_CRV to indicate the NIST P-384 curve, also known as + * secp384r1. + * + * This key type is always \ref COSE_KEY_TYPE_EC2. + */ +#define COSE_ELLIPTIC_CURVE_P_384 2 + +/** + * \def COSE_ELLIPTIC_CURVE_P_521 + * + * \brief Key type for NIST P-521 key + * + * In a \c COSE_Key, this is a value of the data item labeled \ref + * COSE_KEY_PARAM_CRV to indicate the NIST P-521 curve, also known as + * secp521r1. + */ +#define COSE_ELLIPTIC_CURVE_P_521 3 + + + + +/* ------- Constants from RFC 8152 --------- + */ + +/** + * \def COSE_SIG_CONTEXT_STRING_SIGNATURE1 + * + * \brief This is a string constant used by COSE to label \c COSE_Sign1 + * structures. See RFC 8152, section 4.4. + */ +#define COSE_SIG_CONTEXT_STRING_SIGNATURE1 "Signature1" + + +#endif /* __T_COSE_DEFINES_H__ */ diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/t_cose/src/t_cose_sign1_sign.c b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/t_cose/src/t_cose_sign1_sign.c new file mode 100644 index 0000000..8f55bc0 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/t_cose/src/t_cose_sign1_sign.c @@ -0,0 +1,499 @@ +/* + * t_cose_sign1_sign.c + * + * Copyright (c) 2018-2019, Laurence Lundblade. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + * See BSD-3-Clause license in README.md + */ + +#include "t_cose_sign1_sign.h" +#include "qcbor.h" +#include "t_cose_defines.h" +#include "t_cose_crypto.h" +#include "t_cose_util.h" + + +/** + * \file t_cose_sign1_sign.c + * + * \brief This implements t_cose signing + */ + + +/** + * \brief Create a short-circuit signature + * + * \param[in] cose_alg_id Algorithm ID. This is used only to make + * the short-circuit signature the same size + * as the real signature would be for the + * particular algorithm. + * \param[in] hash_to_sign The bytes to sign. Typically, a hash of + * a payload. + * \param[in] signature_buffer Pointer and length of buffer into which + * the resulting signature is put. + * \param[in] signature Pointer and length of the signature + * returned. + * + * \return This returns one of the error codes defined by \ref t_cose_err_t. + * + * This creates the short-circuit signature that is a concatenation of + * hashes up to the expected size of the signature. This is a test + * mode only has it has no security value. This is retained in + * commercial production code as a useful test or demo that can run + * even if key material is not set up or accessible. + */ +static inline enum t_cose_err_t +short_circuit_sign(int32_t cose_alg_id, + struct useful_buf_c hash_to_sign, + struct useful_buf signature_buffer, + struct useful_buf_c *signature) +{ + /* approximate stack use on 32-bit machine: local use: 16 + */ + enum t_cose_err_t return_value; + size_t array_indx; + size_t amount_to_copy; + size_t sig_size; + + sig_size = t_cose_signature_size(cose_alg_id); + + if(sig_size > signature_buffer.len) { + /* Buffer too small for this signature type */ + return_value = T_COSE_ERR_SIG_BUFFER_SIZE; + goto Done; + } + + /* Loop concatening copies of the hash to fill out to signature size */ + for(array_indx = 0; array_indx < sig_size; array_indx += hash_to_sign.len) { + amount_to_copy = sig_size - array_indx; + if(amount_to_copy > hash_to_sign.len) { + amount_to_copy = hash_to_sign.len; + } + memcpy((uint8_t *)signature_buffer.ptr + array_indx, + hash_to_sign.ptr, + amount_to_copy); + } + signature->ptr = signature_buffer.ptr; + signature->len = sig_size; + return_value = T_COSE_SUCCESS; + +Done: + return return_value; +} + + + +/** + * The maximum size of a CBOR Encoded \c COSE_Key that this + * implementation can handle. \c COSE_Key is the serialization format + * for public and other types of keys defined by [COSE (RFC 8152)] + * (https://tools.ietf.org/html/rfc8152). + * + * This can be increased to handle larger keys, but stack usage will + * go up with this increase. + */ +#define MAX_ENCODED_COSE_KEY_SIZE \ + 1 + /* 1 byte to encode map */ \ + 2 + /* 2 bytes to encode key type */ \ + 2 + /* 2 bytes to encode curve */ \ + 2 * /* the X and Y coordinates at 32 bytes each */ \ + (T_COSE_CRYPTO_EC_P256_COORD_SIZE + 1 + 2) + + +/** + * \brief CBOR encode a public key as a \c COSE_Key + * + * \param[in] key_select Identifies the public key to encode. + * + * \param[in] buffer_for_cose_key Pointer and length of buffer into which + * the encoded \c COSE_Key is put. + * \param[in] cose_key Pointer and length of the encoded \c COSE_Key. + * + * \return This returns one of the error codes defined by \ref t_cose_err_t. + * + * \c COSE_Key is the COSE-defined format for serializing a key for + * transmission in a protocol. This function encodes an EC public key + * expressed as an X and Y coordinate. + */ +static enum t_cose_err_t +t_cose_encode_cose_key(int32_t key_select, + struct useful_buf buffer_for_cose_key, + struct useful_buf_c *cose_key) +{ + /* approximate stack use on 32-bit machine: + * local use: 328 + * with calls: 370 + */ + enum t_cose_err_t return_value; + QCBORError qcbor_result; + QCBOREncodeContext cbor_encode_ctx; + USEFUL_BUF_MAKE_STACK_UB( buffer_for_x_coord, + T_COSE_CRYPTO_EC_P256_COORD_SIZE); + USEFUL_BUF_MAKE_STACK_UB( buffer_for_y_coord, + T_COSE_CRYPTO_EC_P256_COORD_SIZE); + struct useful_buf_c x_coord; + struct useful_buf_c y_coord; + int32_t cose_curve_id; + struct useful_buf_c encoded_key_id; + + /* Get the public key x and y */ + return_value = t_cose_crypto_get_ec_pub_key(key_select, + NULL_USEFUL_BUF_C, + &cose_curve_id, + buffer_for_x_coord, + buffer_for_y_coord, + &x_coord, + &y_coord); + if(return_value != T_COSE_SUCCESS) { + goto Done; + } + + /* Encode it into a COSE_Key structure */ + QCBOREncode_Init(&cbor_encode_ctx, buffer_for_cose_key); + QCBOREncode_OpenMap(&cbor_encode_ctx); + QCBOREncode_AddInt64ToMapN(&cbor_encode_ctx, + COSE_KEY_COMMON_KTY, + COSE_KEY_TYPE_EC2); + QCBOREncode_AddInt64ToMapN(&cbor_encode_ctx, + COSE_KEY_PARAM_CRV, + cose_curve_id); + QCBOREncode_AddBytesToMapN(&cbor_encode_ctx, + COSE_KEY_PARAM_X_COORDINATE, + x_coord); + QCBOREncode_AddBytesToMapN(&cbor_encode_ctx, + COSE_KEY_PARAM_Y_COORDINATE, + y_coord); + QCBOREncode_CloseMap(&cbor_encode_ctx); + + qcbor_result = QCBOREncode_Finish(&cbor_encode_ctx, &encoded_key_id); + if(qcbor_result != QCBOR_SUCCESS) { + /* Mainly means that the COSE_Key was too big for buffer_for_cose_key */ + return_value = T_COSE_ERR_PROTECTED_HEADERS; + goto Done; + } + + /* Finish up and return */ + *cose_key = encoded_key_id; + return_value = T_COSE_SUCCESS; + +Done: + return return_value; +} + + +/** + * \brief SHA-256 hash a buffer in one quick function + * + * \param[in] bytes_to_hash The bytes to be hashed. + * + * \param[in] buffer_for_hash Pointer and length into which + * the resulting hash is put. + * \param[out] hash Pointer and length of the + * resulting hash. + * \return This returns one of the error codes defined by \ref t_cose_err_t. + * + * Simple wrapper for start, update and finish interface to a hash. + * + * Having this as a separate function helps keep stack usage down and + * is convenient. + */ +static enum t_cose_err_t quick_sha256(struct useful_buf_c bytes_to_hash, + struct useful_buf buffer_for_hash, + struct useful_buf_c *hash) +{ + /* approximate stack use on 32-bit machine: + local use: 132 + */ + enum t_cose_err_t return_value = 0; + struct t_cose_crypto_hash hash_ctx; + + return_value = t_cose_crypto_hash_start(&hash_ctx, + COSE_ALG_SHA256_PROPRIETARY); + if(return_value) { + goto Done; + } + t_cose_crypto_hash_update(&hash_ctx, bytes_to_hash); + return_value = t_cose_crypto_hash_finish(&hash_ctx, + buffer_for_hash, + hash); + +Done: + return return_value; +} + + +/** + * \brief Make a key ID based on the public key to go in the kid + * unprotected header. + * + * \param[in] key_select Identifies the public key. + * \param[in] buffer_for_key_id Pointer and length into which + * the resulting key ID is put. + * \param[out] key_id Pointer and length of the + * resulting key ID. + * + * \return This returns one of the error codes defined by \ref t_cose_err_t. + * + * + * See t_cose_sign1_init() for documentation of the key ID format + * created here. + */ +static inline enum t_cose_err_t get_keyid(int32_t key_select, + struct useful_buf buffer_for_key_id, + struct useful_buf_c *key_id) +{ + /* approximate stack use on 32-bit machine: + * local use: 100 + * with calls inlined: 560 + * with calls not inlined: 428 + */ + enum t_cose_err_t return_value; + USEFUL_BUF_MAKE_STACK_UB( buffer_for_cose_key, + MAX_ENCODED_COSE_KEY_SIZE); + struct useful_buf_c cose_key; + + /* Doing the COSE encoding and the hashing in separate functions + * called from here reduces the stack usage in this function by a + * lot + */ + + /* Get the key and encode it as a COSE_Key */ + return_value = t_cose_encode_cose_key(key_select, + buffer_for_cose_key, + &cose_key); + if(return_value != T_COSE_SUCCESS) { + goto Done; + } + + /* SHA256 hash of it is all we care about in the end */ + return_value = quick_sha256(cose_key, buffer_for_key_id, key_id); + +Done: + return return_value; +} + + +/** + * \brief Makes the protected headers for COSE. + * + * \param[in] cose_alg_id The COSE algorithm ID to put in the headers. + * + * \param[in] buffer_for_header Pointer and length into which + * the resulting encoded protected + * headers is put. + * + * \return The pointer and length of the protected headers is + * returned, or \c NULL_USEFUL_BUF_C if this fails. + * + * The protected headers are returned in fully encoded CBOR format as + * they are added to the \c COSE_Sign1 as a binary string. This is + * different from the unprotected headers which are not handled this + * way. + * + * This returns \c NULL_USEFUL_BUF_C if buffer_for_header was too + * small. See also definition of \ref T_COSE_SIGN1_MAX_PROT_HEADER + */ +static inline struct useful_buf_c +make_protected_header(int32_t cose_alg_id, + struct useful_buf buffer_for_header) +{ + /* approximate stack use on 32-bit machine: + * local use: 170 + * with calls: 210 + */ + struct useful_buf_c protected_headers; + QCBORError qcbor_result; + QCBOREncodeContext cbor_encode_ctx; + struct useful_buf_c return_value; + + QCBOREncode_Init(&cbor_encode_ctx, buffer_for_header); + QCBOREncode_OpenMap(&cbor_encode_ctx); + QCBOREncode_AddInt64ToMapN(&cbor_encode_ctx, + COSE_HEADER_PARAM_ALG, + cose_alg_id); + QCBOREncode_CloseMap(&cbor_encode_ctx); + qcbor_result = QCBOREncode_Finish(&cbor_encode_ctx, &protected_headers); + + if(qcbor_result == QCBOR_SUCCESS) { + return_value = protected_headers; + } else { + return_value = NULL_USEFUL_BUF_C; + } + + return return_value; +} + + +/** + * \brief Add the unprotected headers to a CBOR encoding context + * + * \param[in] cbor_encode_ctx CBOR encoding context to output to + * \param[in] kid The key ID to go into the kid header. + * + * No error is returned. If an error occurred it will be returned when + * \c QCBOR_Finish() is called on \c cbor_encode_ctx. + * + * The unprotected headers added by this are just the key ID + */ +static inline void add_unprotected_headers(QCBOREncodeContext *cbor_encode_ctx, + struct useful_buf_c kid) +{ + QCBOREncode_OpenMap(cbor_encode_ctx); + QCBOREncode_AddBytesToMapN(cbor_encode_ctx, COSE_HEADER_PARAM_KID, kid); + QCBOREncode_CloseMap(cbor_encode_ctx); +} + + +/* + * Public function. See t_cose_sign1_sign.h + */ +enum t_cose_err_t t_cose_sign1_init(struct t_cose_sign1_ctx *me, + bool short_circuit_sign, + int32_t cose_alg_id, + int32_t key_select, + QCBOREncodeContext *cbor_encode_ctx) +{ + /* approximate stack use on 32-bit machine: + * local use: 66 + * with calls inlined: 900 + * with calls not inlined: 500 + */ + + int32_t hash_alg; + enum t_cose_err_t return_value; + USEFUL_BUF_MAKE_STACK_UB( buffer_for_kid, T_COSE_CRYPTO_SHA256_SIZE); + struct useful_buf_c kid; + struct useful_buf buffer_for_protected_header; + + /* Check the cose_alg_id now by getting the hash alg as an early + error check even though it is not used until later. */ + hash_alg = hash_alg_id_from_sig_alg_id(cose_alg_id); + if(hash_alg == INT32_MAX) { + return T_COSE_ERR_UNSUPPORTED_SIGNING_ALG; + } + + /* Remember all the parameters in the context */ + me->cose_algorithm_id = cose_alg_id; + me->key_select = key_select; + me->short_circuit_sign = short_circuit_sign; + me->cbor_encode_ctx = cbor_encode_ctx; + + /* Get the key id because it goes into the headers that are about + to be made. */ + if(short_circuit_sign) { + return_value = get_short_circuit_kid(buffer_for_kid, &kid); + } else { + return_value = get_keyid(key_select, buffer_for_kid, &kid); + } + if(return_value) { + goto Done; + } + + /* Get started with the tagged array that holds the four parts of + a cose single signed message */ + QCBOREncode_AddTag(cbor_encode_ctx, CBOR_TAG_COSE_SIGN1); + QCBOREncode_OpenArray(cbor_encode_ctx); + + /* The protected headers, which are added as a wrapped bstr */ + buffer_for_protected_header = + USEFUL_BUF_FROM_BYTE_ARRAY(me->buffer_for_protected_headers); + me->protected_headers = make_protected_header(cose_alg_id, + buffer_for_protected_header); + if(useful_buf_c_is_null(me->protected_headers)) { + /* The sizing of storage for protected headers is + off (should never happen in tested, released code) */ + return_value = T_COSE_SUCCESS; + goto Done; + } + QCBOREncode_AddBytes(cbor_encode_ctx, me->protected_headers); + + /* The Unprotected headers */ + add_unprotected_headers(cbor_encode_ctx, kid); + + /* Any failures in CBOR encoding will be caught in finish + when the CBOR encoding is closed off. No need to track + here as the CBOR encoder tracks it internally. */ + + return_value = T_COSE_SUCCESS; + +Done: + return return_value; +} + + +/* + * Public function. See t_cose_sign1_sign.h + */ +enum t_cose_err_t t_cose_sign1_finish(struct t_cose_sign1_ctx *me, + struct useful_buf_c signed_payload) +{ + /* approximate stack use on 32-bit machine: + * local use: 116 + * with calls inline: 500 + * with calls not inlined; 450 + */ + enum t_cose_err_t return_value; + /* pointer and length of the completed tbs hash */ + struct useful_buf_c tbs_hash; + /* Pointer and length of the completed signature */ + struct useful_buf_c signature; + /* Buffer for the actual signature */ + USEFUL_BUF_MAKE_STACK_UB( buffer_for_signature, + T_COSE_MAX_EC_SIG_SIZE); + /* Buffer for the tbs hash. Only big enough for SHA256 */ + USEFUL_BUF_MAKE_STACK_UB( buffer_for_tbs_hash, + T_COSE_CRYPTO_SHA256_SIZE); + + /* Create the hash of the to-be-signed bytes. Inputs to the hash + * are the protected headers, the payload that getting signed, the + * cose signature alg from which the hash alg is determined. The + * cose_algorithm_id was checked in t_cose_sign1_init() so it + * doesn't need to be checked here. + */ + return_value = create_tbs_hash(me->cose_algorithm_id, + buffer_for_tbs_hash, + &tbs_hash, + me->protected_headers, + signed_payload); + if(return_value) { + goto Done; + } + + /* Compute the signature using public key crypto. The key selector + * and algorithm ID are passed in to know how and what to sign + * with. The hash of the TBS bytes are what is signed. A buffer in + * which to place the signature is passed in and the signature is + * returned. + * + * Short-circuit signing is invoked if requested. It does no + * public key operation and requires no key. It is just a test + * mode that always works. + */ + if(me->short_circuit_sign) { + return_value = short_circuit_sign(me->cose_algorithm_id, + tbs_hash, + buffer_for_signature, + &signature); + } else { + return_value = t_cose_crypto_pub_key_sign(me->cose_algorithm_id, + me->key_select, + tbs_hash, + buffer_for_signature, + &signature); + } + if(return_value) { + goto Done; + } + + /* Add signature to CBOR and close out the array */ + QCBOREncode_AddBytes(me->cbor_encode_ctx, signature); + QCBOREncode_CloseArray(me->cbor_encode_ctx); + + /* CBOR encoding errors are tracked in the CBOR encoding context + and handled in the layer above this */ + +Done: + return return_value; +} diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/t_cose/src/t_cose_util.c b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/t_cose/src/t_cose_util.c new file mode 100644 index 0000000..ba4910e --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/t_cose/src/t_cose_util.c @@ -0,0 +1,189 @@ +/* + * t_cose_util.c + * + * Copyright 2019, Laurence Lundblade + * + * SPDX-License-Identifier: BSD-3-Clause + * + * See BSD-3-Clause license in README.mdE. + */ + +#include "t_cose_util.h" +#include "qcbor.h" +#include "t_cose_defines.h" +#include "t_cose_common.h" +#include "t_cose_crypto.h" + + +/** + * \file t_cose_util.c + * + * \brief Implementation of t_cose utility functions. + * + */ + + +/* + * Public function. See t_cose_util.h + */ +int32_t hash_alg_id_from_sig_alg_id(int32_t cose_sig_alg_id) +{ + /* if other hashes, particularly those that output bigger hashes + * are added here, various other parts of this code have to be + * changed to have larger buffers. + */ + switch(cose_sig_alg_id) { + + case COSE_ALGORITHM_ES256: + return COSE_ALG_SHA256_PROPRIETARY; + + default: + return INT32_MAX; + } +} + + +/* + * Format of to-be-signed bytes used by create_tbs_hash(). + * This is defined in COSE (RFC 8152). It is the input + * to the hash. + * + * Sig_structure = [ + * context : "Signature" / "Signature1" / "CounterSignature", + * body_protected : empty_or_serialized_map, + * ? sign_protected : empty_or_serialized_map, + * external_aad : bstr, + * payload : bstr + * ] + */ + + +/** + * This is the size of the first part of the CBOR encoded TBS + * bytes. It is around 20 bytes. See create_tbs_hash(). + */ +#define T_COSE_SIZE_OF_TBS \ + 1 + /* For opening the array */ \ + sizeof(COSE_SIG_CONTEXT_STRING_SIGNATURE1) + /* "Signature1" */ \ + 2 + /* Overhead for encoding string */ \ + T_COSE_SIGN1_MAX_PROT_HEADER + /* entire protected headers */ \ + 3 * ( /* 3 NULL bstrs for fields not used */ \ + 1 /* size of a NULL bstr */ \ + ) + + +/* + * Public function. See t_cose_util.h + */ +enum t_cose_err_t create_tbs_hash(int32_t cose_alg_id, + struct useful_buf buffer_for_hash, + struct useful_buf_c *hash, + struct useful_buf_c protected_headers, + struct useful_buf_c payload) +{ + /* approximate stack use on 32-bit machine: + * local use: 320 + * with calls: 360 + */ + enum t_cose_err_t return_value; + QCBOREncodeContext cbor_encode_ctx; + UsefulBuf_MAKE_STACK_UB( buffer_for_TBS_first_part, T_COSE_SIZE_OF_TBS); + struct useful_buf_c tbs_first_part; + QCBORError qcbor_result; + struct t_cose_crypto_hash hash_ctx; + int32_t hash_alg_id; + + /* This builds the CBOR-format to-be-signed bytes */ + QCBOREncode_Init(&cbor_encode_ctx, buffer_for_TBS_first_part); + QCBOREncode_OpenArray(&cbor_encode_ctx); + /* context */ + QCBOREncode_AddSZString(&cbor_encode_ctx, + COSE_SIG_CONTEXT_STRING_SIGNATURE1); + /* body_protected */ + QCBOREncode_AddBytes(&cbor_encode_ctx, + protected_headers); + /* sign_protected */ + QCBOREncode_AddBytes(&cbor_encode_ctx, NULL_USEFUL_BUF_C); + /* external_aad */ + QCBOREncode_AddBytes(&cbor_encode_ctx, NULL_USEFUL_BUF_C); + /* fake payload */ + QCBOREncode_AddBytes(&cbor_encode_ctx, NULL_USEFUL_BUF_C); + QCBOREncode_CloseArray(&cbor_encode_ctx); + + /* get the result and convert it to struct useful_buf_c representation */ + qcbor_result = QCBOREncode_Finish(&cbor_encode_ctx, &tbs_first_part); + if(qcbor_result) { + /* Mainly means that the protected_headers were too big + (which should never happen) */ + return_value = T_COSE_ERR_SIG_STRUCT; + goto Done; + } + + /* Start the hashing */ + hash_alg_id = hash_alg_id_from_sig_alg_id(cose_alg_id); + /* Don't check hash_alg_id for failure. t_cose_crypto_hash_start() + will handle it properly + */ + return_value = t_cose_crypto_hash_start(&hash_ctx, hash_alg_id); + if(return_value) { + goto Done; + } + + /* Hash the first part of the TBS. Take all but the last two + * bytes. The last two bytes are the fake payload from above. It + * is replaced by the real payload which is hashed next. The fake + * payload is needed so the array count is right. This is one of + * the main things that make it possible to implement with one + * buffer for the whole cose sign1. + */ + t_cose_crypto_hash_update(&hash_ctx, + useful_buf_head(tbs_first_part, + tbs_first_part.len - 2)); + + /* Hash the payload */ + t_cose_crypto_hash_update(&hash_ctx, payload); + + /* Finish the hash and set up to return it */ + return_value = t_cose_crypto_hash_finish(&hash_ctx, + buffer_for_hash, + hash); + +Done: + return return_value; +} + + +/* + * Public function. See t_cose_util.h + */ +enum t_cose_err_t +get_short_circuit_kid(struct useful_buf buffer_for_kid, + struct useful_buf_c *kid) +{ + /* This is a random hard coded key ID that is used to indicate + * short-circuit signing. It is OK to hard code this as the + * probability of collision with this ID is very low and the same + * as for collision between any two key IDs of any sort. + */ + uint8_t defined_short_circuit_kid[] = { + 0xef, 0x95, 0x4b, 0x4b, 0xd9, 0xbd, 0xf6, 0x70, + 0xd0, 0x33, 0x60, 0x82, 0xf5, 0xef, 0x15, 0x2a, + 0xf8, 0xf3, 0x5b, 0x6a, 0x6c, 0x00, 0xef, 0xa6, + 0xa9, 0xa7, 0x1f, 0x49, 0x51, 0x7e, 0x18, 0xc6}; + + /* Prevent a dumb error where the size constant in the header is + * wrong.This check will be evaluated at compile time and optimize + * out when all is correct. + */ + if(sizeof(defined_short_circuit_kid) != T_COSE_SHORT_CIRCUIT_KID_SIZE) { + return T_COSE_ERR_BAD_SHORT_CIRCUIT_KID; + } + + *kid = useful_buf_copy(buffer_for_kid, + USEFUL_BUF_FROM_BYTE_ARRAY_LITERAL( + defined_short_circuit_kid)); + + return useful_buf_c_is_null(*kid) ? + T_COSE_ERR_KEY_BUFFER_SIZE : + T_COSE_SUCCESS; +} diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/t_cose/src/t_cose_util.h b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/t_cose/src/t_cose_util.h new file mode 100644 index 0000000..7b39dc3 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/t_cose/src/t_cose_util.h @@ -0,0 +1,126 @@ +/* + * t_cose_util.h + * + * Copyright 2019, Laurence Lundblade + * + * SPDX-License-Identifier: BSD-3-Clause + * + * See BSD-3-Clause license in README.mdE. + */ + + +#ifndef __T_COSE_UTIL_H__ +#define __T_COSE_UTIL_H__ + +#include +#include "useful_buf.h" +#include "t_cose_common.h" + +/** + * \file t_cose_util.h + * + * \brief Utility functions used internally by the t_cose implementation. + * + */ + + +/** + * \brief Return hash algorithm ID from a signature algorithm ID + * + * \param[in] cose_sig_alg_id A COSE signature algorithm identifier. + * + * \return \c INT32_MAX when the signature algorithm ID is not known. + * + * This works off of algorithm identifiers defined in the [IANA COSE + * Registry] (https://www.iana.org/assignments/cose/cose.xhtml). + * Corresponding local integer constants are defined in + * t_cose_defines.h. + * + * COSE signing algorithms are the combination of public key + * algorithm, curve, key size, hash algorithm and hash size. They are + * simple integers making them convenient for direct use in code. + * + * This function returns an identifier for only the hash algorithm + * from the combined identifier. + * + * If the needed algorithm identifiers are not in the IANA registry, + * they can be added to it. This will take some time and work. It is + * also fine to use algorithms in the proprietary space. + */ +int32_t hash_alg_id_from_sig_alg_id(int32_t cose_sig_alg_id); + + +/** + * \brief Create the hash of the to-be-signed (TBS) bytes for COSE. + * + * \param[in] cose_alg_id The COSE signing algorithm ID. Used to + * determine which hash function to use. + * \param[in] buffer_for_hash Pointer and length of buffer into which + * the resulting hash is put. + * \param[out] hash Pointer and length of the + * resulting hash. + * \param[in] protected_headers The CBOR encoded protected headers. + * \param[in] payload The CBOR encoded payload + * + * \return This returns one of the error codes defined by \ref t_cose_err_t. + * + * \retval T_COSE_ERR_SIG_STRUCT + * Most likely this is because the protected_headers passed in + * is larger than \ref T_COSE_SIGN1_MAX_PROT_HEADER. + * \retval T_COSE_ERR_UNSUPPORTED_HASH + * If the hash algorithm is not known. + * \retval T_COSE_ERR_HASH_GENERAL_FAIL + * In case of some general hash failure. + * + * The input to the public key signature algorithm in COSE is the hash + * of a CBOR encoded structure containing the protected headers + * algorithm ID and a few other things. This formats that structure + * and computes the hash of it. These are known as the to-be-signed or + * "TBS" bytes. + */ +enum t_cose_err_t create_tbs_hash(int32_t cose_alg_id, + struct useful_buf buffer_for_hash, + struct useful_buf_c *hash, + struct useful_buf_c protected_headers, + struct useful_buf_c payload); + + +/** + * Size of the key returned by get_short_circuit_kid(). It is always + * this size. + */ +#define T_COSE_SHORT_CIRCUIT_KID_SIZE 32 + + +/** + * \brief Get the special kid for short-circuit signing. + * + * \param[in] buffer_for_kid Pointer and length of buffer into which + * the resulting hash is put. It should + * always be at least \ref + * T_COSE_SHORT_CIRCUIT_KID_SIZE. + * \param[out] kid Pointer and length of the returned kid. + * + * \retval T_COSE_SUCCESS + * The kid was returned. + * \retval T_COSE_ERR_KEY_BUFFER_SIZE + * \c buffer_for_kid is too small + * + * This always returns the same key ID. It always indicates + * short-circuit signing. It is OK to hard code this as the + * probability of collision with this ID is extremely low and the same + * as for collision between any two key IDs (kids) of any sort. + * + * This is the value of the kid. + * + * 0xef, 0x95, 0x4b, 0x4b, 0xd9, 0xbd, 0xf6, 0x70, + * 0xd0, 0x33, 0x60, 0x82, 0xf5, 0xef, 0x15, 0x2a, + * 0xf8, 0xf3, 0x5b, 0x6a, 0x6c, 0x00, 0xef, 0xa6, + * 0xa9, 0xa7, 0x1f, 0x49, 0x51, 0x7e, 0x18, 0xc6 + * + */ +enum t_cose_err_t +get_short_circuit_kid(struct useful_buf buffer_for_kid, + struct useful_buf_c *kid); + +#endif /* __T_COSE_UTIL_H__ */ diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/tfm_attest_hal.h b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/tfm_attest_hal.h new file mode 100755 index 0000000..b43b109 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/tfm_attest_hal.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2019, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#ifndef __TFM_ATTEST_HAL_H__ +#define __TFM_ATTEST_HAL_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Security lifecycle of the device + */ +enum tfm_security_lifecycle_t { + TFM_SLC_UNKNOWN = 0x0000u, + TFM_SLC_ASSEMBLY_AND_TEST = 0x1000u, + TFM_SLC_PSA_ROT_PROVISIONING = 0x2000u, + TFM_SLC_SECURED = 0x3000u, + TFM_SLC_NON_PSA_ROT_DEBUG = 0x4000u, + TFM_SLC_RECOVERABLE_PSA_ROT_DEBUG = 0x5000u, + TFM_SLC_DECOMMISSIONED = 0x6000u, +}; + +/** + * \brief Retrieve the security lifecycle of the device + * + * Security lifecycle is a mandatory claim in the initial attestation token. + * + * \return According to \ref tfm_security_lifecycle_t + */ +enum tfm_security_lifecycle_t tfm_attest_hal_get_security_lifecycle(void); + +/** + * \brief Retrieve the verification service indicator for initial attestation. + * + * It is used by relying party to locate a validation service for the token. + * It can be a text string that can be used to locate the service or can be a + * URL specifying the address of the service. + * + * \param[out] size Length of the string, without the termination zero byte. + * + * \return NULL pointer if not available otherwise the address of the + * verification service string in the device memory. + */ +const char * +tfm_attest_hal_get_verification_service(uint32_t *size); + +/** + * \brief Retrieve the name of the profile definition document for initial + * attestation. + * + * This document describes the 'profile' of the initial attestation token, + * being a full description of the claims, their usage, verification and + * token signing. + * + * \param[out] size Length of the document name, without the termination zero + * byte. + * + * \return NULL pointer if not available otherwise the address of the document + * name string in the device memory. + */ +const char * +tfm_attest_hal_get_profile_definition(uint32_t *size); + +#ifdef __cplusplus +} +#endif + +#endif /* __TFM_ATTEST_HAL_H__ */ diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/tfm_boot_status.h b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/tfm_boot_status.h new file mode 100755 index 0000000..dbcc6ce --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/tfm_boot_status.h @@ -0,0 +1,207 @@ +/* + * Copyright (c) 2018-2019, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#ifndef __TFM_BOOT_STATUS_H__ +#define __TFM_BOOT_STATUS_H__ + +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif + +/* Major numbers (4 bit) to identify + * the consumer of shared data in runtime SW + */ +#define TLV_MAJOR_CORE 0x0 +#define TLV_MAJOR_IAS 0x1 + +/** + * The shared data between boot loader and runtime SW is TLV encoded. The + * shared data is stored in a well known location in secure memory and this is + * a contract between boot loader and runtime SW. + * + * The structure of shared data must be the following: + * - At the beginning there must be a header: struct shared_data_tlv_header + * This contains a magic number and a size field which covers the entire + * size of the shared data area including this header. + * - After the header there come the entries which are composed from an entry + * header structure: struct shared_data_tlv_entry and the data. In the entry + * header is a type field (tly_type) which identify the consumer of the + * entry in the runtime SW and specify the subtype of that data item. There + * is a size field (tlv_len) which covers the size of the entry header and + * the data. After this structure comes the actual data. + * - Arbitrary number and size of data entry can be in the shared memory area. + * + * This table gives of overview about the tlv_type field in the entry header. + * The tlv_type always composed from a major and minor number. Major number + * identifies the addressee in runtime SW, who should process the data entry. + * Minor number used to encode more info about the data entry. The actual + * definition of minor number could change per major number. In case of boot + * status data, which is going to be processed by initial attestation service + * the minor number is split further to two part: sw_module and claim. The + * sw_module identifies the SW component in the system which the data item + * belongs to and the claim part identifies the exact type of the data. + * + * |---------------------------------------| + * | tlv_type (16) | + * |---------------------------------------| + * | tlv_major(4)| tlv_minor(12) | + * |---------------------------------------| + * | MAJOR_IAS | sw_module(6) | claim(6) | + * |---------------------------------------| + * | MAJOR_CORE | TBD | + * |---------------------------------------| + */ + +/* Initial attestation: SW components / SW modules + * This list is intended to be adjusted per device. It contains more SW + * components than currently available in TF-M project. It serves as an example, + * what kind of SW components might be available. + */ +#define SW_GENERAL 0x00 +#define SW_BL2 0x01 +#define SW_PROT 0x02 +#define SW_AROT 0x03 +#define SW_SPE 0x04 +#define SW_NSPE 0x05 +#define SW_S_NS 0x06 +#define SW_MAX 0x07 + +/* Initial attestation: Claim per SW components / SW modules */ +/* Bits: 0-2 */ +#define SW_VERSION 0x00 +#define SW_SIGNER_ID 0x01 +#define SW_EPOCH 0x02 +#define SW_TYPE 0x03 +/* Bits: 3-5 */ +#define SW_MEASURE_VALUE 0x08 +#define SW_MEASURE_TYPE 0x09 + +/* Initial attestation: General claim does not belong any particular SW + * component. But they might be part of the boot status. + */ +#define BOOT_SEED 0x00 +#define HW_VERSION 0x01 +#define SECURITY_LIFECYCLE 0x02 + +/* Minor numbers (12 bit) to identify attestation service related data */ +#define TLV_MINOR_IAS_BOOT_SEED ((SW_GENERAL << 6) | BOOT_SEED) +#define TLV_MINOR_IAS_HW_VERSION ((SW_GENERAL << 6) | HW_VERSION) +#define TLV_MINOR_IAS_SLC ((SW_GENERAL << 6) | SECURITY_LIFECYCLE) + +/* Bootloader - It can be more stage */ +#define TLV_MINOR_IAS_BL2_MEASURE_VALUE ((SW_BL2 << 6) | SW_MEASURE_VALUE) +#define TLV_MINOR_IAS_BL2_MEASURE_TYPE ((SW_BL2 << 6) | SW_MEASURE_TYPE) +#define TLV_MINOR_IAS_BL2_VERSION ((SW_BL2 << 6) | SW_VERSION) +#define TLV_MINOR_IAS_BL2_SIGNER_ID ((SW_BL2 << 6) | SW_SIGNER_ID) +#define TLV_MINOR_IAS_BL2_EPOCH ((SW_BL2 << 6) | SW_EPOCH) +#define TLV_MINOR_IAS_BL2_TYPE ((SW_BL2 << 6) | SW_TYPE) + +/* PROT: PSA Root of Trust */ +#define TLV_MINOR_IAS_PROT_MEASURE_VALUE ((SW_PROT << 6) | SW_MEASURE_VALUE) +#define TLV_MINOR_IAS_PROT_MEASURE_TYPE ((SW_PROT << 6) | SW_MEASURE_TYPE) +#define TLV_MINOR_IAS_PROT_VERSION ((SW_PROT << 6) | SW_VERSION) +#define TLV_MINOR_IAS_PROT_SIGNER_ID ((SW_PROT << 6) | SW_SIGNER_ID) +#define TLV_MINOR_IAS_PROT_EPOCH ((SW_PROT << 6) | SW_EPOCH) +#define TLV_MINOR_IAS_PROT_TYPE ((SW_PROT << 6) | SW_TYPE) + +/* AROT: Application Root of Trust */ +#define TLV_MINOR_IAS_AROT_MEASURE_VALUE ((SW_AROT << 6) | SW_MEASURE_VALUE) +#define TLV_MINOR_IAS_AROT_MEASURE_TYPE ((SW_AROT << 6) | SW_MEASURE_TYPE) +#define TLV_MINOR_IAS_AROT_VERSION ((SW_AROT << 6) | SW_VERSION) +#define TLV_MINOR_IAS_AROT_SIGNER_ID ((SW_AROT << 6) | SW_SIGNER_ID) +#define TLV_MINOR_IAS_AROT_EPOCH ((SW_AROT << 6) | SW_EPOCH) +#define TLV_MINOR_IAS_AROT_TYPE ((SW_AROT << 6) | SW_TYPE) + +/* Non-secure processing environment - single non-secure image */ +#define TLV_MINOR_IAS_NSPE_MEASURE_VALUE ((SW_NSPE << 6) | SW_MEASURE_VALUE) +#define TLV_MINOR_IAS_NSPE_MEASURE_TYPE ((SW_NSPE << 6) | SW_MEASURE_TYPE) +#define TLV_MINOR_IAS_NSPE_VERSION ((SW_NSPE << 6) | SW_VERSION) +#define TLV_MINOR_IAS_NSPE_SIGNER_ID ((SW_NSPE << 6) | SW_SIGNER_ID) +#define TLV_MINOR_IAS_NSPE_EPOCH ((SW_NSPE << 6) | SW_EPOCH) +#define TLV_MINOR_IAS_NSPE_TYPE ((SW_NSPE << 6) | SW_TYPE) + +/* Secure processing environment (ARoT + PRoT) - single secure image */ +#define TLV_MINOR_IAS_SPE_MEASURE_VALUE ((SW_SPE << 6) | SW_MEASURE_VALUE) +#define TLV_MINOR_IAS_SPE_MEASURE_TYPE ((SW_SPE << 6) | SW_MEASURE_TYPE) +#define TLV_MINOR_IAS_SPE_VERSION ((SW_SPE << 6) | SW_VERSION) +#define TLV_MINOR_IAS_SPE_SIGNER_ID ((SW_SPE << 6) | SW_SIGNER_ID) +#define TLV_MINOR_IAS_SPE_EPOCH ((SW_SPE << 6) | SW_EPOCH) +#define TLV_MINOR_IAS_SPE_TYPE ((SW_SPE << 6) | SW_TYPE) + +/* SPE + NSPE - combined secure and non-secure image */ +#define TLV_MINOR_IAS_S_NS_MEASURE_VALUE ((SW_S_NS << 6) | SW_MEASURE_VALUE) +#define TLV_MINOR_IAS_S_NS_MEASURE_TYPE ((SW_S_NS << 6) | SW_MEASURE_TYPE) +#define TLV_MINOR_IAS_S_NS_VERSION ((SW_S_NS << 6) | SW_VERSION) +#define TLV_MINOR_IAS_S_NS_SIGNER_ID ((SW_S_NS << 6) | SW_SIGNER_ID) +#define TLV_MINOR_IAS_S_NS_EPOCH ((SW_S_NS << 6) | SW_EPOCH) +#define TLV_MINOR_IAS_S_NS_TYPE ((SW_S_NS << 6) | SW_TYPE) + +/* General macros to handle TLV type */ +#define MAJOR_MASK 0xF /* 4 bit */ +#define MAJOR_POS 12 /* 12 bit */ +#define MINOR_MASK 0xFFF /* 12 bit */ + +#define SET_TLV_TYPE(major, minor) \ + ((((major) & MAJOR_MASK) << MAJOR_POS) | ((minor) & MINOR_MASK)) +#define GET_MAJOR(tlv_type) ((tlv_type) >> MAJOR_POS) +#define GET_MINOR(tlv_type) ((tlv_type) & MINOR_MASK) + +/* Initial attestation specific macros */ +#define MODULE_POS 6 /* 6 bit */ +#define CLAIM_MASK 0x3F /* 6 bit */ +#define MEASUREMENT_CLAIM_POS 3 /* 3 bit */ + +#define GET_IAS_MODULE(tlv_type) (GET_MINOR(tlv_type) >> MODULE_POS) +#define GET_IAS_CLAIM(tlv_type) (GET_MINOR(tlv_type) & CLAIM_MASK) +#define SET_IAS_MINOR(sw_module, claim) (((sw_module) << 6) | (claim)) + +#define GET_IAS_MEASUREMENT_CLAIM(ias_claim) ((ias_claim) >> \ + MEASUREMENT_CLAIM_POS) + +/* Magic value which marks the beginning of shared data area in memory */ +#define SHARED_DATA_TLV_INFO_MAGIC 0x2016 + +/** + * Shared data TLV header. All fields in little endian. + * + * ----------------------------------- + * | tlv_magic(16) | tlv_tot_len(16) | + * ----------------------------------- + */ +struct shared_data_tlv_header { + uint16_t tlv_magic; + uint16_t tlv_tot_len; /* size of whole TLV area (including this header) */ +}; + +#define SHARED_DATA_HEADER_SIZE sizeof(struct shared_data_tlv_header) + +/** + * Shared data TLV entry header format. All fields in little endian. + * + * ------------------------------- + * | tlv_type(16) | tlv_len(16) | + * ------------------------------- + * | Raw data | + * ------------------------------- + */ +struct shared_data_tlv_entry { + uint16_t tlv_type; + uint16_t tlv_len; /* size of single TLV entry (including this header). */ +}; + +#define SHARED_DATA_ENTRY_HEADER_SIZE sizeof(struct shared_data_tlv_entry) +#define SHARED_DATA_ENTRY_SIZE(size) (size + SHARED_DATA_ENTRY_HEADER_SIZE) + +#ifdef __cplusplus +} +#endif + +#endif /* __TFM_BOOT_STATUS_H__ */ diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/tfm_plat_boot_seed.h b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/tfm_plat_boot_seed.h new file mode 100755 index 0000000..11b79f0 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/tfm_plat_boot_seed.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2018, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#ifndef __TFM_PLAT_BOOT_SEED_H__ +#define __TFM_PLAT_BOOT_SEED_H__ +/** + * \file tfm_plat_boot_seed.h + * + * Boot seed is used by a validating entity to ensure multiple reports were + * generated in the same boot session. Boot seed is a random number, generated + * only once during a boot cycle and its value is constant in the same cycle. + * Size recommendation is 256-bit to meet the statistically improbable property. + * Boot seed can be generated by secure boot loader an included to the measured + * boot state or can be generated by PRoT SW. + */ + +/** + * \note The interfaces defined in this file must be implemented for each + * SoC. + */ + +#include +#include "tfm_plat_defs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * \def BOOT_SEED_SIZE + * + * \brief Size of boot seed in bytes. + */ +#define BOOT_SEED_SIZE (32u) + +/** + * \brief Gets the boot seed, which is a constant random number during a boot + * cycle. + * + * \param[in] size The required size of boot seed in bytes + * \param[out] buf Pointer to the buffer to store boot seed + * + * \return TFM_PLAT_ERR_SUCCESS if the value is generated correctly. Otherwise, + * it returns TFM_PLAT_ERR_SYSTEM_ERR. + */ +enum tfm_plat_err_t tfm_plat_get_boot_seed(uint32_t size, uint8_t *buf); + +#ifdef __cplusplus +} +#endif + +#endif /* __TFM_PLAT_BOOT_SEED_H__ */ diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/tfm_plat_crypto_keys.h b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/tfm_plat_crypto_keys.h new file mode 100755 index 0000000..386d61f --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/tfm_plat_crypto_keys.h @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2017-2019, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#ifndef __TFM_PLAT_CRYPTO_KEYS_H__ +#define __TFM_PLAT_CRYPTO_KEYS_H__ +/** + * \note The interfaces defined in this file must be implemented for each + * SoC. + */ + +#include +#include "tfm_plat_defs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Elliptic curve key type identifiers according to RFC8152 (COSE encoding) + * https://www.iana.org/assignments/cose/cose.xhtml#elliptic-curves + */ +enum ecc_curve_t { + P_256 = 1, /* NIST P-256 also known as secp256r1 */ + P_384 = 2, /* NIST P-384 also known as secp384r1 */ + P_521 = 3, /* NIST P-521 also known as secp521r1 */ + X25519 = 4, /* X25519 for use with ECDH only */ + X448 = 5, /* X448 for use with ECDH only */ + ED25519 = 6, /* Ed25519 for use with EdDSA only */ + ED448 = 7, /* Ed448 for use with EdDSA only */ +}; + +/** + * Structure definition to carry pointer and size information about an Elliptic + * curve key which is stored in a buffer(key_buf) in raw format (without + * encoding): + * - priv_key Base address of the private key in key_buf. It must be + * present on the device. + * - priv_key_size Size of the private key in bytes. + * - pubx_key Base address of x-coordinate of the public key in key_buf. + * It can be empty, because it can be recomputed based on + * private key. + * - pubx_key_size Length of x-coordinate of the public key in key_buf. + * It can be empty, because it can be recomputed based on + * private key. + * - puby_key Base address of y-coordinate of the public key in key_buf. + * It can be empty, because either it can be recomputed based + * on private key or some curve type works without it. + * - puby_key_size Length of y-coordinate of the public key in key_buf. + */ +struct ecc_key_t { + uint8_t *priv_key; + uint32_t priv_key_size; + uint8_t *pubx_key; + uint32_t pubx_key_size; + uint8_t *puby_key; + uint32_t puby_key_size; +}; + +#define ECC_P_256_KEY_SIZE (96u) /* 3 x 32 = 96 bytes priv + pub-x + pub-y */ + +/** + * \brief Gets hardware unique key for encryption + * + * \param[out] key Buf to store the key in + * \param[in] size Size of the buffer + * + * \return Returns error code specified in \ref tfm_plat_err_t + */ +enum tfm_plat_err_t tfm_plat_get_crypto_huk(uint8_t *key, uint32_t size); + +/** + * \brief Get the initial attestation key + * + * The device MUST contain an initial attestation key, which is used to sign the + * token. Initial attestation service supports elliptic curve signing + * algorithms. Device maker can decide whether store only the private key on the + * device or store both (public and private) key. Public key can be recomputed + * based on private key. Keys must be provided in raw format, just binary data + * without any encoding (DER, COSE). Caller provides a buffer to copy all the + * available key components to there. Key components must be copied after + * each other to the buffer. The base address and the length of each key + * component must be indicating in the corresponding field of ecc_key + * (\ref struct ecc_key_t). + * Curve_type indicates to which curve belongs the key. + * + * + * Keys must be provided in + * + * \param[in/out] key_buf Buffer to store the initial attestation key. + * \param[in] size Size of the buffer. + * \param[out] ecc_key A structure to carry pointer and size information + * about the initial attestation key, which is + * stored in key_buf. + * \param[out] curve_type The type of the EC curve, which the key belongs + * to according to \ref ecc_curve_t + * + * \return Returns error code specified in \ref tfm_plat_err_t + */ +enum tfm_plat_err_t +tfm_plat_get_initial_attest_key(uint8_t *key_buf, + uint32_t size, + struct ecc_key_t *ecc_key, + enum ecc_curve_t *curve_type); + +#ifdef __cplusplus +} +#endif + +#endif /* __TFM_PLAT_CRYPTO_KEYS_H__ */ diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/tfm_plat_defs.h b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/tfm_plat_defs.h new file mode 100755 index 0000000..66747ee --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/tfm_plat_defs.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2017-2018, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#ifndef __TFM_PLAT_DEFS_H__ +#define __TFM_PLAT_DEFS_H__ +/** + * \note The interfaces defined in this file must be implemented for each + * target. + */ + +#include +#include + +enum tfm_plat_err_t { + TFM_PLAT_ERR_SUCCESS = 0, + TFM_PLAT_ERR_SYSTEM_ERR, + TFM_PLAT_ERR_MAX_VALUE, + /* Following entry is only to ensure the error code of int size */ + TFM_PLAT_ERR_FORCE_INT_SIZE = INT_MAX +}; + +/*! + * \def TFM_LINK_SET_OBJECT_IN_PARTITION_SECTION(TFM_PARTITION_NAME) + * + * \brief This macro provides a mechanism to place a function code in a specific + * secure partition at linker time in TF-M Level 3. + * + * \param[in] TFM_PARTITION_NAME TF-M partition name assigned in the manifest + * file "tfm_partition_name" field. + */ +#define TFM_LINK_SET_OBJECT_IN_PARTITION_SECTION(TFM_PARTITION_NAME) \ + __attribute__((section(TFM_PARTITION_NAME"_ATTR_FN"))) + +#endif /* __TFM_PLAT_DEFS_H__ */ diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/tfm_plat_device_id.h b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/tfm_plat_device_id.h new file mode 100755 index 0000000..dcce837 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/tfm_plat_device_id.h @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2018-2019, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#ifndef __TFM_PLAT_DEVICE_ID_H__ +#define __TFM_PLAT_DEVICE_ID_H__ +/** + * \file tfm_plat_device_id.h + * + * The interfaces defined in this file are meant to provide the following + * attributes of the device: + * - Instance ID: Unique identifier of the device. + * - Implementation ID: Original implementation signer of the attestation key. + * - Hardware version: Identify the GDSII that went to fabrication. + */ + +/** + * \note The interfaces defined in this file must be implemented for each + * SoC. + */ + +#include +#include "tfm_plat_defs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \def INSTANCE_ID_MAX_SIZE + * + * \brief Maximum size of instance ID in bytes + */ +#define INSTANCE_ID_MAX_SIZE (33u) + +/** + * \def IMPLEMENTATION_ID_MAX_SIZE + * + * \brief Maximum size of implementation ID in bytes + */ +#define IMPLEMENTATION_ID_MAX_SIZE (32u) + +/** + * \def HW_VERSION_MAX_SIZE + * + * \brief Maximum size of hardware version in bytes + * + * Recommended to use the European Article Number format: EAN-13+5 + */ +#define HW_VERSION_MAX_SIZE (18u) + +/** + * \brief Get the UEID of the device. + * + * This mandatory claim represents the unique identifier of the instance. + * In the PSA definition is a hash of the public attestation key of the + * instance. The claim will be represented by the EAT standard claim UEID + * of type GUID. The EAT definition of a GUID type is that it will be between + * 128 & 256 bits but this implementation will use the full 256 bits to + * accommodate a hash result. + * + * \param[in/out] size As an input value it indicates the size of the caller + * allocated buffer (in bytes) to store the UEID. At return + * its value is updated with the exact size of the UEID. + * \param[out] buf Pointer to the buffer to store the UEID + * + * \return Returns error code specified in \ref tfm_plat_err_t + */ +enum tfm_plat_err_t tfm_plat_get_instance_id(uint32_t *size, uint8_t *buf); + +/** + * \brief Get the Implementation ID of the device. + * + * This mandatory claim represents the original implementation signer of the + * attestation key and identifies the contract between the report and + * verification. A verification service will use this claim to locate the + * details of the verification process. The claim will be represented by a + * custom EAT claim with a value consisting of a CBOR byte string. The size of + * this string will normally be 32 bytes to accommodate a 256 bit hash. + * + * \param[in/out] size As an input value it indicates the size of the caller + * allocated buffer (in bytes) to store the implementation + * ID. At return its value is updated with the exact size + * of the implementation ID. + * \param[out] buf Pointer to the buffer to store the implementation ID + * + * \return Returns error code specified in \ref tfm_plat_err_t + */ +enum tfm_plat_err_t tfm_plat_get_implementation_id(uint32_t *size, + uint8_t *buf); + +/** + * \brief Get the hardware version of the device. + * + * This optional claim provides metadata linking the token to the GDSII that + * went to fabrication for this instance. It is represented as CBOR text string. + * It is recommended to use for identification the format of the European + * Article Number: EAN-13+5. + * + * \param[in/out] size As an input value it indicates the size of the caller + * allocated buffer (in bytes) to store the HW version. At + * return its value is updated with the exact size of the + * HW version. + * \param[out] buf Pointer to the buffer to store the HW version + * + * \return Returns error code specified in \ref tfm_plat_err_t + */ +enum tfm_plat_err_t tfm_plat_get_hw_version(uint32_t *size, uint8_t *buf); + +#ifdef __cplusplus +} +#endif + +#endif /* __TFM_PLAT_DEVICE_ID_H__ */ diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_memory_utils.h b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_memory_utils.h new file mode 100644 index 0000000..852399e --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_memory_utils.h @@ -0,0 +1,39 @@ +/* +* Copyright (c) 2018-2019 ARM Limited. All rights reserved. +* +* SPDX-License-Identifier: Apache-2.0 +* +* Licensed under the Apache License, Version 2.0 (the License); you may +* not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an AS IS BASIS, WITHOUT +* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#ifndef __TFM_MEMORY_UTILS_H__ +#define __TFM_MEMORY_UTILS_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + +void *tfm_memcpy(void *dest, const void *src, size_t num) +{ + return (memcpy(dest, src, num)); +} + +#ifdef __cplusplus +} +#endif + +#endif /* __TFM_MEMORY_UTILS_H__ */ diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IPC/psa_attest_inject_key.c b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IPC/psa_attest_inject_key.c new file mode 100755 index 0000000..239b8d3 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IPC/psa_attest_inject_key.c @@ -0,0 +1,55 @@ +/* +* Copyright (c) 2018-2019 ARM Limited. All rights reserved. +* +* SPDX-License-Identifier: Apache-2.0 +* +* Licensed under the Apache License, Version 2.0 (the License); you may +* not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an AS IS BASIS, WITHOUT +* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include "psa_attest_inject_key.h" +#include "psa/crypto.h" +#include "psa/client.h" +#include "psa_manifest/sid.h" + +#define MINOR_VER 1 + +psa_status_t +psa_attestation_inject_key(const uint8_t *key_data, + size_t key_data_length, + psa_key_type_t type, + uint8_t *public_key_data, + size_t public_key_data_size, + size_t *public_key_data_length) +{ + psa_handle_t handle = PSA_NULL_HANDLE; + psa_status_t call_error = PSA_SUCCESS; + psa_invec in_vec[2] = { + { &type, sizeof(type) }, + { key_data, key_data_length } + }; + + psa_outvec out_vec[2] = { + { public_key_data, public_key_data_size }, + { public_key_data_length, sizeof(*public_key_data_length) } + }; + + handle = psa_connect(PSA_ATTEST_INJECT_KEY_ID, MINOR_VER); + if (handle <= 0) { + return (PSA_ERROR_COMMUNICATION_FAILURE); + } + + call_error = psa_call(handle, in_vec, 2, out_vec, 2); + + psa_close(handle); + return call_error; +} diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IPC/psa_initial_attestation_api.c b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IPC/psa_initial_attestation_api.c new file mode 100755 index 0000000..ff90cc8 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/COMPONENT_PSA_SRV_IPC/psa_initial_attestation_api.c @@ -0,0 +1,79 @@ +/* +* Copyright (c) 2018-2019 ARM Limited. All rights reserved. +* +* SPDX-License-Identifier: Apache-2.0 +* +* Licensed under the Apache License, Version 2.0 (the License); you may +* not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an AS IS BASIS, WITHOUT +* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include "psa_initial_attestation_api.h" +#include "psa/crypto.h" +#include "psa/client.h" +#include "attestation.h" +#include +#include "psa_manifest/sid.h" + +#define MINOR_VER 1 + +enum psa_attest_err_t +psa_initial_attest_get_token(const uint8_t *challenge_obj, + uint32_t challenge_size, + uint8_t *token, + uint32_t *token_size) { + psa_status_t err_call; + psa_handle_t handle = PSA_NULL_HANDLE; + + psa_invec in_vec[1] = { { challenge_obj, challenge_size } }; + psa_outvec out_vec[1] = { { token, *token_size } }; + + handle = psa_connect(PSA_ATTEST_GET_TOKEN_ID, MINOR_VER); + if (handle <= 0) + { + return (PSA_ATTEST_ERR_GENERAL); + } + + err_call = psa_call(handle, in_vec, 1, out_vec, 1); + psa_close(handle); + + if (err_call < 0) + { + err_call = PSA_ATTEST_ERR_GENERAL; + } + + return ((enum psa_attest_err_t) err_call); +} + +enum psa_attest_err_t +psa_initial_attest_get_token_size(uint32_t challenge_size, + uint32_t *token_size) { + psa_status_t err_call; + psa_handle_t handle = PSA_NULL_HANDLE; + psa_invec in_vec[1] = { { &challenge_size, sizeof(uint32_t) } }; + psa_outvec out_vec[1] = { { token_size, sizeof(uint32_t) } }; + + handle = psa_connect(PSA_ATTEST_GET_TOKEN_SIZE_ID, MINOR_VER); + if (handle <= 0) + { + return (PSA_ATTEST_ERR_GENERAL); + } + + err_call = psa_call(handle, in_vec, 1, out_vec, 1); + psa_close(handle); + + if (err_call < 0) + { + err_call = PSA_ATTEST_ERR_GENERAL; + } + + return ((enum psa_attest_err_t) err_call); +} diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/LICENSE b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/LICENSE new file mode 100644 index 0000000..96810fd --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/LICENSE @@ -0,0 +1,2 @@ +Unless specifically indicated otherwise in a file, TF-M files in this directory are licensed under the BSD-3-Clause license, +as can be found in: LICENSE-bsd-3-clause.txt diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/LICENSE-BSD-3-Clause b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/LICENSE-BSD-3-Clause new file mode 100644 index 0000000..476769c --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/LICENSE-BSD-3-Clause @@ -0,0 +1,26 @@ +Copyright 2019 Arm Limited and affiliates. +SPDX-License-Identifier: BSD-3-Clause + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. Neither the name of the copyright holder nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/attestation.h b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/attestation.h new file mode 100755 index 0000000..b2b8d1b --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/attestation.h @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2018-2019, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +/** @addtogroup PSA-Attestation + * @{ + */ + + +#ifndef __ATTESTATION_H__ +#define __ATTESTATION_H__ + +#include "psa_initial_attestation_api.h" +#include "tfm_client.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Type of memory access + */ +enum attest_memory_access_t { + TFM_ATTEST_ACCESS_RO = 1, + TFM_ATTEST_ACCESS_RW = 2, +}; + +/** + * \brief Copy the boot data (coming from boot loader) from shared memory area + * to service memory area + * + * \param[in] major_type Major type of TLV entries to copy + * \param[out] ptr Pointer to the buffer to store the boot data + * \parma[in] len Size of the buffer to store the boot data + * + * \return Returns error code as specified in \ref psa_attest_err_t + */ +enum psa_attest_err_t +attest_get_boot_data(uint8_t major_type, void *ptr, uint32_t len); + +/** + * \brief Get the ID of the caller thread. + * + * \param[out] caller_id Pointer where to store caller ID + * + * \return Returns error code as specified in \ref psa_attest_err_t + */ +enum psa_attest_err_t +attest_get_caller_client_id(int32_t *caller_id); + +/** + * \brief Verify memory access rights + * + * \param[in] addr Pointer to the base of the address range to check + * \param[in] size Size of the address range to check + * \param[in] access Type of memory access as specified in + * \ref attest_memory_access + * + * \return Returns error code as specified in \ref psa_attest_err_t + */ +enum psa_attest_err_t +attest_check_memory_access(void *addr, + uint32_t size, + enum attest_memory_access_t access); + +/** + * \brief Initialise the initial attestation service during the TF-M boot up + * process. + * + * \return Returns PSA_ATTEST_ERR_SUCCESS if init has been completed, + * otherwise error as specified in \ref psa_attest_err_t + */ +enum psa_attest_err_t attest_init(void); + +/** + * \brief Get initial attestation token + * + * \param[in] in_vec Pointer to in_vec array, which contains input data + * to attestation service + * \param[in] num_invec Number of elements in in_vec array + * \param[in/out] out_vec Pointer out_vec array, which contains output data + * to attestation service + * \param[in] num_outvec Number of elements in out_vec array + * + * \return Returns error code as specified in \ref psa_attest_err_t + */ +enum psa_attest_err_t +initial_attest_get_token(const psa_invec *in_vec, uint32_t num_invec, + psa_outvec *out_vec, uint32_t num_outvec); + +/** + * \brief Get the size of the initial attestation token + * + * \param[in] in_vec Pointer to in_vec array, which contains input data + * to attestation service + * \param[in] num_invec Number of elements in in_vec array + * \param[out] out_vec Pointer to out_vec array, which contains pointer + * where to store the output data + * \param[in] num_outvec Number of elements in out_vec array + * + * \return Returns error code as specified in \ref psa_attest_err_t + */ +enum psa_attest_err_t +initial_attest_get_token_size(const psa_invec *in_vec, uint32_t num_invec, + psa_outvec *out_vec, uint32_t num_outvec); +#ifdef __cplusplus +} +#endif + +/** @}*/ // PSA-Attestation + +#endif /* __ATTESTATION_H__ */ diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/psa_attest_inject_key.h b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/psa_attest_inject_key.h new file mode 100644 index 0000000..3e934d3 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/psa_attest_inject_key.h @@ -0,0 +1,87 @@ +/* +* Copyright (c) 2018-2019 ARM Limited. All rights reserved. +* +* SPDX-License-Identifier: Apache-2.0 +* +* Licensed under the Apache License, Version 2.0 (the License); you may +* not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an AS IS BASIS, WITHOUT +* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +/** @addtogroup PSA-Attestation + * @{ + */ + +#ifndef __PSA_INJECT_KEY_H__ +#define __PSA_INJECT_KEY_H__ + +#include "psa/crypto.h" +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + +/** + * \brief Generate or import a given key pair and export the public part in a binary format. + * Initial attestation key: Private key for ECDSA-P256 to sign initial attestation token. + * Attestation private key is a persistent key that saved to + * persistent storage with persistent storage id = 17. + * + * \param[in] key_data Buffer containing the private key data if given. + * It must conain the format described in the documentation + * of psa_export_public_key() for + * the chosen type. + * In case of generate the private key - NULL will pass. + * \param key_data_length Size of the \p data buffer in bytes - must be 256 bits. in case key_data isn't NULL. + * In case of private key generation - 0 will pass. + * \param type Key type - must be a ECC key type + * (a \c PSA_KEY_TYPE_ECC_KEYPAIR(PSA_ECC_CURVE_XXX) value). + * \param[out] data Buffer where the key data is to be written. + * \param data_size Size of the \p data buffer in bytes - + * needs to be bigger then the max size of the public part. + * \param[out] data_length On success, the number of bytes + * that make up the key data. + * + * \retval #PSA_SUCCESS + * Success. + * \retval #PSA_ERROR_INVALID_HANDLE + * \retval #PSA_ERROR_OCCUPIED_SLOT + * There is already a key in the specified slot. + * \retval #PSA_ERROR_NOT_SUPPORTED + * \retval #PSA_ERROR_INVALID_ARGUMENT + * \retval #PSA_ERROR_INSUFFICIENT_MEMORY + * \retval #PSA_ERROR_INSUFFICIENT_ENTROPY + * \retval #PSA_ERROR_COMMUNICATION_FAILURE + * \retval #PSA_ERROR_HARDWARE_FAILURE + * \retval #PSA_ERROR_TAMPERING_DETECTED + * \retval #PSA_ERROR_BAD_STATE + * The library has not been previously initialized by psa_crypto_init(). + * It is implementation-dependent whether a failure to initialize + * results in this error code. + */ +psa_status_t +psa_attestation_inject_key(const uint8_t *key_data, + size_t key_data_length, + psa_key_type_t type, + uint8_t *public_key_data, + size_t public_key_data_size, + size_t *public_key_data_length); + +#ifdef __cplusplus +} +#endif + +/** @}*/ // PSA-Attestation + +#endif /* __PSA_INJECT_KEY_H__ */ diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/psa_initial_attestation_api.h b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/psa_initial_attestation_api.h new file mode 100644 index 0000000..0b56499 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/psa_initial_attestation_api.h @@ -0,0 +1,233 @@ +/* + * Copyright (c) 2018-2019, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +/***************************************************************************/ +/* DRAFT UNDER REVIEW */ +/* These APIs are still evolving and are meant as a prototype for review.*/ +/* The APIs will change depending on feedback and will be firmed up */ +/* to a stable set of APIs once all the feedback has been considered. */ +/***************************************************************************/ + +/** @addtogroup PSA-Attestation + * @{ + */ + + +#ifndef __PSA_INITIAL_ATTESTATION_API_H__ +#define __PSA_INITIAL_ATTESTATION_API_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief PSA INITIAL ATTESTATION API version + */ +#define PSA_INITIAL_ATTEST_API_VERSION_MAJOR (0) +#define PSA_INITIAL_ATTEST_API_VERSION_MINOR (9) + +/** + * \enum psa_attest_err_t + * + * \brief Initial attestation service error types + * + */ +enum psa_attest_err_t { + /** Action was performed successfully */ + PSA_ATTEST_ERR_SUCCESS = 0, + /** Boot status data is unavailable or malformed */ + PSA_ATTEST_ERR_INIT_FAILED, + /** Token buffer is too small to store the created token there */ + PSA_ATTEST_ERR_TOKEN_BUFFER_OVERFLOW, + /** Some of the mandatory claims are unavailable*/ + PSA_ATTEST_ERR_CLAIM_UNAVAILABLE, + /** Some parameter or combination of parameters are recognised as invalid: + * - challenge size is not allowed + * - challenge object is unavailable + * - token buffer is unavailable + */ + PSA_ATTEST_ERR_INVALID_INPUT, + /** Unexpected error happened during operation */ + PSA_ATTEST_ERR_GENERAL, + /** Following entry is only to ensure the error code of integer size */ + PSA_ATTEST_ERR_FORCE_INT_SIZE = INT_MAX +}; + +/** + * The allowed size of input challenge in bytes: 32, 48, 64 + * Challenge can be a nonce from server + * or the hash of some combined data : nonce + attested data by caller. + */ +#define PSA_INITIAL_ATTEST_CHALLENGE_SIZE_32 (32u) +#define PSA_INITIAL_ATTEST_CHALLENGE_SIZE_48 (48u) +#define PSA_INITIAL_ATTEST_CHALLENGE_SIZE_64 (64u) + +/** + * The list of fixed claims in the initial attestation token is still evolving, + * you can expect slight changes in the future. + * + * The initial attestation token is planned to be aligned with future version of + * Entity Attestation Token format: + * https://tools.ietf.org/html/draft-mandyam-eat-01 + * + * Current list of claims: + * - Challenge: Input object from caller. Can be a single nonce from server + * or hash of nonce and attested data. It is intended to provide + * freshness to reports and the caller has responsibility to + * arrange this. Allowed length: 32, 48, 64 bytes. The claim is + * modeled to be eventually represented by the EAT standard + * claim nonce. Until such a time as that standard exists, + * the claim will be represented by a custom claim. Value + * is encoded as byte string. + * + * - Instance ID: It represents the unique identifier of the instance. In the + * PSA definition it is a hash of the public attestation key + * of the instance. The claim is modeled to be eventually + * represented by the EAT standard claim UEID of type GUID. + * Until such a time as that standard exists, the claim will be + * represented by a custom claim Value is encoded as byte + * string. + * + * - Verification service indicator: Optional, recommended claim. It is used by + * a Relying Party to locate a validation service for the token. + * The value is a text string that can be used to locate the + * service or a URL specifying the address of the service. The + * claim is modeled to be eventually represented by the EAT + * standard claim origination. Until such a time as that + * standard exists, the claim will be represented by a custom + * claim. Value is encoded as text string. + * + * - Profile definition: Optional, recommended claim. It contains the name of + * a document that describes the 'profile' of the token, being + * a full description of the claims, their usage, verification + * and token signing. The document name may include versioning. + * Custom claim with a value encoded as text string. + * + * - Implementation ID: It represents the original implementation signer of the + * attestation key and identifies the contract between the + * report and verification. A verification service will use this + * claim to locate the details of the verification process. + * Custom claim with a value encoded as byte string. + * + * - Security lifecycle: It represents the current lifecycle state of the + * instance. Custom claim with a value encoded as integer that + * is divided to convey a major state and a minor state. The + * PSA state and implementation state are encoded as follows: + * - version[15:8] - PSA lifecycle state - major + * - version[7:0] - IMPLEMENTATION DEFINED state - minor + * Possible PSA lifecycle states: + * - Unknown (0x1000u), + * - PSA_RoT_Provisioning (0x2000u), + * - Secured (0x3000u), + * - Non_PSA_RoT_Debug(0x4000u), + * - Recoverable_PSA_RoT_Debug (0x5000u), + * - Decommissioned (0x6000u) + * + * - Client ID: The partition ID of that secure partition or non-secure + * thread who called the initial attestation API. Custom claim + * with a value encoded as a *signed* integer. Negative number + * represents non-secure caller, positive numbers represents + * secure callers, zero is invalid. + * + * - HW version: Optional claim. Globally unique number in EAN-13 format + * identifying the GDSII that went to fabrication, HW and ROM. + * It can be used to reference the security level of the PSA-ROT + * via a certification website. Custom claim with a value is + * encoded as text string. + + * - Boot seed: It represents a random value created at system boot time that + * will allow differentiation of reports from different system + * sessions. The size is 32 bytes. Custom claim with a value is + * encoded as byte string. + * + * - Software components: Recommended claim. It represents the software state + * of the system. The value of the claim is an array of CBOR map + * entries, with one entry per software component within the + * device. Each map contains multiple claims that describe + * evidence about the details of the software component. + * + * - Measurement type: Optional claim. It represents the role of the + * software component. Value is encoded as short(!) text + * string. + * + * - Measurement value: It represents a hash of the invariant software + * component in memory at start-up time. The value must be a + * cryptographic hash of 256 bits or stronger.Value is + * encoded as byte string. + * + * - Security epoch: Optional claim. It represents the security control + * point of the software component. Value is encoded as + * unsigned integer. + * + * - Version: Optional claim. It represents the issued software version. + * Value is encoded as text string. + * + * - Signer ID: It represents the hash of a signing authority public key. + * Value is encoded as byte string. + * + * - Measurement description: Optional claim. It represents the way in which + * the measurement value of the software component is + * computed. Value is encoded as text string containing an + * abbreviated description (name) of the measurement method. + * + * - No software measurements: In the event that the implementation does not + * contain any software measurements then the software + * components claim above can be omitted but instead + * it is mandatory to include this claim to indicate this is a + * deliberate state. Custom claim a value is encoded as unsigned + * integer set to 1. + */ + +/** + * \brief Get initial attestation token + * + * \param[in] challenge_obj Pointer to buffer where challenge input is + * stored. Nonce and / or hash of attested data. + * Must be always + * \ref PSA_INITIAL_ATTEST_CHALLENGE_SIZE bytes + * long. + * \param[in] challenge_size Size of challenge object in bytes. + * \param[out] token Pointer to the buffer where attestation token + * must be stored. + * \param[in/out] token_size Size of allocated buffer for token, which + * updated by initial attestation service with + * final token size. + * + * \return Returns error code as specified in \ref psa_attest_err_t + */ +enum psa_attest_err_t +psa_initial_attest_get_token(const uint8_t *challenge_obj, + uint32_t challenge_size, + uint8_t *token, + uint32_t *token_size); + +/** + * \brief Get the exact size of initial attestation token in bytes. + * + * It just returns with the size of the IAT token. It can be used if the caller + * dynamically allocates memory for the token buffer. + * + * \param[in] challenge_size Size of challenge object in bytes. + * \param[out] token_size Size of the token in bytes, which is created by + * initial attestation service. + * + * \return Returns error code as specified in \ref psa_attest_err_t + */ +enum psa_attest_err_t +psa_initial_attest_get_token_size(uint32_t challenge_size, + uint32_t *token_size); + +#ifdef __cplusplus +} +#endif + +/** @}*/ // PSA-Attestation + +#endif /* __PSA_INITIAL_ATTESTATION_API_H__ */ diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/qcbor/.mbedignore b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/qcbor/.mbedignore new file mode 100644 index 0000000..ab1cfb4 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/qcbor/.mbedignore @@ -0,0 +1 @@ +test/* diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/qcbor/CMakeLists.txt b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/qcbor/CMakeLists.txt new file mode 100644 index 0000000..060462a --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/qcbor/CMakeLists.txt @@ -0,0 +1,41 @@ +#------------------------------------------------------------------------------- +# Copyright (c) 2019, Arm Limited. All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# +#------------------------------------------------------------------------------- + +cmake_minimum_required(VERSION 3.7) + +#Tell cmake where our modules can be found +list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/../../../cmake) + +#Include common stuff to control cmake. +include("Common/BuildSys") + +#Start an embedded project. +embedded_project_start(CONFIG "${CMAKE_CURRENT_LIST_DIR}/../../../ConfigDefault.cmake") +project(tfm_qcbor LANGUAGES C) +embedded_project_fixup() + +#Some project global settings +set (QCBOR_DIR "${CMAKE_CURRENT_LIST_DIR}") + +#Append all our source files to global lists. +list(APPEND ALL_SRC_C + "${QCBOR_DIR}/src/ieee754.c" + "${QCBOR_DIR}/src/qcbor_decode.c" + "${QCBOR_DIR}/src/qcbor_encode.c" + "${QCBOR_DIR}/src/UsefulBuf.c" + ) + +#Setting include directories +embedded_include_directories(PATH ${QCBOR_DIR}/inc ABSOLUTE) + +#Specify what we build (for the QCBOR, build as an object library) +add_library(${PROJECT_NAME} OBJECT ${ALL_SRC_C}) + +#Set common compiler flags +config_setting_shared_compiler_flags(${PROJECT_NAME}) + +embedded_project_end(${PROJECT_NAME}) diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/qcbor/README.md b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/qcbor/README.md new file mode 100644 index 0000000..58a7080 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/qcbor/README.md @@ -0,0 +1,175 @@ +# QCBOR + +QCBOR encodes and decodes [RFC 7049](https://tools.ietf.org/html/rfc7049) CBOR. + +## Characteristics + +**Implemented in C with minimal dependency** – Only dependencies are + C99, , , and making it + highly portable. There are no #ifdefs to be configured at all. + +**Focused on C / native data representation** – Simpler code because + there is no support for encoding/decoding to/from JSON, pretty + printing, diagnostic notation... Only encoding from native C + representations and decoding to native C representations is supported. + +**Small simple memory model** – Malloc is not needed. The encode + context is 136 bytes, decode context is 104 bytes and the + description of decoded data item is 56 bytes. Stack use is light and + there is no recursion. The caller supplies the memory to hold the + encoded CBOR and encode/decode contexts so caller has full control + of memory usage making it good for embedded implementations that + have to run in small fixed memory. + +**Supports nearly all of RFC 7049** – Only minor, corner-case parts of + RFC 7049 are not directly supported (canonicalization, decimal + fractions, big floats). Decoding indefinite length strings is supported, + but requires a string allocator (see documentation). Encoding indefinite + length strings is not supported, but is also not necessary or + preferred. + +**Extensible and general** – Provides a way to handle data types that + are not directly supported. + +**Secure coding style** – Uses a construct called UsefulBuf as a + discipline for very safe coding the handling of binary data. + +**Small code size** – When optimized for size using the compiler -Os + option, x86 code is about 4KB (~1.1KB encode, ~2.5KB decode, + ~0.4KB common). Other decoders may be smaller, but they may + also do less for you, so overall size of the implementation may + be larger. For example, QCBOR internally tracks error status + so you don't have to check a return code on every operation. + +**Clear documented public interface** – The public interface is + separated from the implementation. It can be put to use without + reading the source. + +**Comprehensive test suite** – Easy to verify on a new platform + or OS with the test suite. The test suite dependencies are also + minimal, only additionally requiring for floating point + tests. + +## Code Status + +QCBOR was originally developed by Qualcomm. It was [open sourced +through CAF](https://source.codeaurora.org/quic/QCBOR/QCBOR/) with a +permissive Linux license, September 2018 (thanks Qualcomm!). + +This code in [Laurence's +GitHub](https://github.com/laurencelundblade/QCBOR) has diverged from +the CAF source with some small simplifications and tidying up. + +From Nov 3, 2018, the interface and code are fairly stable. Large +changes are not planned or expected, particularly in the +interface. The test coverage is pretty good. + +## Building + +There is a simple makefile for the UNIX style command line binary that +compiles everything to run the tests. + +These seven files, the contents of the src and inc directories, make +up the entire implementation. + +* inc + * UsefulBuf.h + * qcbor.h +* src + * UsefulBuf.c + * qcbor_encode.c + * qcbor_decode.c + * ieee754.h + * ieee754.c + +For most use cases you should just be able to add them to your +project. Hopefully the easy portability of this implementation makes +this work straight away, whatever your development environment is. + +The files ieee754.c and ieee754.h are support for half-precision +floating point. The encoding side of the floating point functionality +is about 500 bytes. If it is never called because no floating point +numbers are ever encoded, all 500 bytes will be dead stripped and not +impact code size. The decoding side is about 150 bytes of object +code. It is never dead stripped because it directly referenced by the +core decoder, however it doesn't add very much to the size. + +The test directory includes some tests that are nearly as portable as +the main implementation. If your development environment doesn't +support UNIX style command line and make, you should be able to make a +simple project and add the test files to it. Then just call +RunTests() to invoke them all. + + +## Changes from CAF Version +* Float support is restored +* Minimal length float encoding is added +* indefinite length arrays/maps are supported +* indefinite length strings are supported +* Tag decoding is changed; unlimited number of tags supported, any tag +value supported, tag utility function for easier tag checking +* Addition functions in UsefulBuf +* QCBOREncode_Init takes a UsefulBuf instead of a pointer and size +* QCBOREncode_Finish takes a UsefulBufC and EncodedCBOR is remove +* bstr wrapping of arrays/maps is replaced with OpenBstrwrap +* AddRaw renamed to AddEncoded and can now only add whole arrays or maps, +not partial maps and arrays (simplification; was a dangerous feature) +* Finish cannot be called repeatedly on a partial decode (some tests used +this, but it is not really a good thing to use in the first place) +* UsefulOutBuf_OutUBuf changed to work differently +* UsefulOutBuf_Init works differently +* The "_3" functions are replaced with a small number of simpler functions +* There is a new AddTag functon instead of the "_3" functions, making +the interface simpler and saving some code +* QCBOREncode_AddRawSimple_2 is removed (the macros that referenced +still exist and work the same) + +## Credits +* Ganesh Kanike for porting to QSEE +* Mark Bapst for sponsorship and release as open source by Qualcomm +* Sachin Sharma for release through CAF +* Tamas Ban for porting to TF-M and 32-bit ARM + +## Copyright and License + +QCBOR is available under what is essentially the 3-Clause BSD License. + +Files created inside Qualcomm and open-sourced through CAF (The Code +Aurora Forum) have a slightly modified 3-Clause BSD License. The +modification additionally disclaims NON-INFRINGEMENT. + +Files created after release to CAF use the standard 3-Clause BSD +License with no modification. These files have the SPDX license +identifier, "SPDX-License-Identifier: BSD-3-Clause" in them. + +### BSD-3-Clause license + +* Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +### Copyright for this README + +Copyright (c) 2018-2019, Laurence Lundblade. All rights reserved. + + + diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/qcbor/inc/UsefulBuf.h b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/qcbor/inc/UsefulBuf.h new file mode 100644 index 0000000..fa17b6c --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/qcbor/inc/UsefulBuf.h @@ -0,0 +1,1536 @@ +/*============================================================================== + Copyright (c) 2016-2018, The Linux Foundation. + Copyright (c) 2018-2019, Laurence Lundblade. + All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of The Linux Foundation nor the names of its + contributors, nor the name "Laurence Lundblade" may be used to + endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ==============================================================================*/ + +/*=================================================================================== + FILE: UsefulBuf.h + + DESCRIPTION: General purpose input and output buffers + + EDIT HISTORY FOR FILE: + + This section contains comments describing changes made to the module. + Notice that changes are listed in reverse chronological order. + + when who what, where, why + -------- ---- --------------------------------------------------- + 12/17/2018 llundblade Remove const from UsefulBuf and UsefulBufC .len + 12/13/2018 llundblade Documentation improvements + 09/18/2018 llundblade Cleaner distinction between UsefulBuf and UsefulBufC + 02/02/18 llundbla Full support for integers in and out; fix pointer + alignment bug. Incompatible change: integers in/out + are now in network byte order. + 08/12/17 llundbla Added UsefulOutBuf_AtStart and UsefulBuf_Find + 06/27/17 llundbla Fix UsefulBuf_Compare() bug. Only affected comparison + for < or > for unequal length buffers. Added + UsefulBuf_Set() function. + 05/30/17 llundbla Functions for NULL UsefulBufs and const / unconst + 11/13/16 llundbla Initial Version. + + + =====================================================================================*/ + +#ifndef _UsefulBuf_h +#define _UsefulBuf_h + + +#include // for uint8_t, uint16_t.... +#include // for strlen, memcpy, memmove, memset +#include // for size_t + +/** + @file UsefulBuf.h + + The goal of this code is to make buffer and pointer manipulation + easier and safer when working with binary data. + + You use the UsefulBuf, UsefulOutBuf and UsefulInputBuf + structures to represent buffers rather than ad hoc pointers and lengths. + + With these it will often be possible to write code that does little or no + direct pointer manipulation for copying and formatting data. For example + the QCBOR encoder was rewritten using these and has no direct pointer + manipulation. + + While it is true that object code using these functions will be a little + larger and slower than a white-knuckle clever use of pointers might be, but + not by that much or enough to have an affect for most use cases. For + security-oriented code this is highly worthwhile. Clarity, simplicity, + reviewability and are more important. + + There are some extra sanity and double checks in this code to help catch + coding errors and simple memory corruption. They are helpful, but not a + substitute for proper code review, input validation and such. + + This code consists of a lot of inline functions and a few that are not. + It should not generate very much object code, especially with the + optimizer turned up to -Os or -O3. The idea is that the inline + functions are easier to review and understand and the optimizer does + the work of making the code small. + */ + + +/*...... This is a ruler that is 80 characters long...........................*/ + +/** + UsefulBufC and UsefulBuf are simple data structures to hold a pointer and + length for a binary data. In C99 this data structure can be passed on the + stack making a lot of code cleaner than carrying around a pointer and + length as two parameters. + + This is also conducive to secure code practice as the lengths are + always carried with the pointer and the convention for handling a + pointer and a length is clear. + + While it might be possible to write buffer and pointer code more + efficiently in some use cases, the thought is that unless there is an + extreme need for performance (e.g., you are building a gigabit-per-second + IP router), it is probably better to have cleaner code you can be most + certain about the security of. + + The non-const UsefulBuf is usually used to refer a buffer to be filled in. + The length is the size of the buffer. + + The const UsefulBufC is usually used to refer to some data that has been + filled in. The length is amount of valid data pointed to. + + A common use is to pass a UsefulBuf to a function, the function fills it + in, the function returns a UsefulBufC. The pointer is the same in both. + + A UsefulBuf is NULL, it has no value, when the ptr in it is NULL. + + There are utility functions for the following: + - Checking for UsefulBufs that are NULL, empty or both + - Copying, copying with offset, copying head or tail + - Comparing and finding substrings + - Initializating + - Create initialized const UsefulBufC from compiler literals + - Create initialized const UsefulBufC from NULL-terminated string + - Make an empty UsefulBuf on the stack + + See also UsefulOutBuf. It is a richer structure that has both the size of + the valid data and the size of the buffer. + + UsefulBuf is only 16 or 8 bytes on a 64- or 32-bit machine so it can go + on the stack and be a function parameter or return value. + + UsefulBuf is kind of like the Useful Pot Pooh gave Eeyore on his birthday. + Eeyore's balloon fits beautifully, "it goes in and out like anything". + +*/ +typedef struct useful_buf_c { + const void *ptr; + size_t len; +} UsefulBufC; + + +/** + The non-const UsefulBuf typically used for some allocated memory + that is to be filled in. The len is the amount of memory, + not the length of the valid data in the buffer. + */ +typedef struct useful_buf { + void *ptr; + size_t len; +} UsefulBuf; + + +/** + A "NULL" UsefulBufC is one that has no value in the same way a NULL pointer has no value. + A UsefulBuf is NULL when the ptr field is NULL. It doesn't matter what len is. + See UsefulBuf_IsEmpty() for the distinction between NULL and empty. + */ +#define NULLUsefulBufC ((UsefulBufC) {NULL, 0}) + +/** A NULL UsefulBuf is one that has no memory associated the say way + NULL points to nothing. It does not matter what len is. + */ +#define NULLUsefulBuf ((UsefulBuf) {NULL, 0}) + + +/** + @brief Check if a UsefulBuf is NULL or not + + @param[in] UB The UsefulBuf to check + + @return 1 if it is NULL, 0 if not. + */ +static inline int UsefulBuf_IsNULL(UsefulBuf UB) { + return !UB.ptr; +} + + +/** + @brief Check if a UsefulBufC is NULL or not + + @param[in] UB The UsefulBufC to check + + @return 1 if it is NULL, 0 if not. + */ +static inline int UsefulBuf_IsNULLC(UsefulBufC UB) { + return !UB.ptr; +} + + +/** + @brief Check if a UsefulBuf is empty or not + + @param[in] UB The UsefulBuf to check + + @return 1 if it is empty, 0 if not. + + An "Empty" UsefulBuf is one that has a value and can be considered to be set, + but that value is of zero length. It is empty when len is zero. It + doesn't matter what the ptr is. + + A lot of uses will not need to clearly distinguish a NULL UsefulBuf + from an empty one and can have the ptr NULL and the len 0. However + if a use of UsefulBuf needs to make a distinction then ptr should + not be NULL when the UsefulBuf is considered empty, but not NULL. + + */ +static inline int UsefulBuf_IsEmpty(UsefulBuf UB) { + return !UB.len; +} + + +/** + @brief Check if a UsefulBufC is empty or not + + @param[in] UB The UsefulBufC to check + + @return 1 if it is empty, 0 if not. + */ +static inline int UsefulBuf_IsEmptyC(UsefulBufC UB) { + return !UB.len; +} + + +/** + @brief Check if a UsefulBuf is NULL or empty + + @param[in] UB The UsefulBuf to check + + @return 1 if it is either NULL or empty, 0 if not. + */ +static inline int UsefulBuf_IsNULLOrEmpty(UsefulBuf UB) { + return UsefulBuf_IsEmpty(UB) || UsefulBuf_IsNULL(UB); +} + + +/** + @brief Check if a UsefulBufC is NULL or empty + + @param[in] UB The UsefulBufC to check + + @return 1 if it is either NULL or empty, 0 if not. + */ +static inline int UsefulBuf_IsNULLOrEmptyC(UsefulBufC UB) { + return UsefulBuf_IsEmptyC(UB) || UsefulBuf_IsNULLC(UB); +} + + +/** + @brief Convert a non const UsefulBuf to a const UsefulBufC + + @param[in] UB The UsefulBuf to convert + + Returns: a UsefulBufC struct + */ + +static inline UsefulBufC UsefulBuf_Const(const UsefulBuf UB) +{ + return (UsefulBufC){UB.ptr, UB.len}; +} + + +/** + @brief Convert a const UsefulBufC to a non-const UsefulBuf + + @param[in] UBC The UsefulBuf to convert + + Returns: a non const UsefulBuf struct + */ +static inline UsefulBuf UsefulBuf_Unconst(const UsefulBufC UBC) +{ + return (UsefulBuf){(void *)UBC.ptr, UBC.len}; +} + + +/** + Convert a literal string to a UsefulBufC. + + szString must be a literal string that you can take sizeof. + This is better for literal strings than UsefulBuf_FromSZ() + because it generates less code. It will not work on + non-literal strings. + + The terminating \0 (NULL) is NOT included in the length! + + */ +#define UsefulBuf_FROM_SZ_LITERAL(szString) \ + ((UsefulBufC) {(szString), sizeof(szString)-1}) + + +/** + Convert a literal byte array to a UsefulBufC. + + pBytes must be a literal string that you can take sizeof. + It will not work on non-literal arrays. + + */ +#define UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pBytes) \ + ((UsefulBufC) {(pBytes), sizeof(pBytes)}) + + +/** + Make an automatic variable with name of type UsefulBuf and point it to a stack + variable of the give size + */ +#define UsefulBuf_MAKE_STACK_UB(name, size) \ + uint8_t __pBuf##name[(size)];\ + UsefulBuf name = {__pBuf##name , sizeof( __pBuf##name )} + + +/** + Make a byte array in to a UsefulBuf + */ +#define UsefulBuf_FROM_BYTE_ARRAY(pBytes) \ + ((UsefulBuf) {(pBytes), sizeof(pBytes)}) + +/** + @brief Convert a NULL terminated string to a UsefulBufC. + + @param[in] szString The string to convert + + @return a UsefulBufC struct + + UsefulBufC.ptr points to the string so it's lifetime + must be maintained. + + The terminating \0 (NULL) is NOT included in the length! + + */ +static inline UsefulBufC UsefulBuf_FromSZ(const char *szString){ + return ((UsefulBufC) {szString, strlen(szString)}); +} + + +/** + @brief Copy one UsefulBuf into another at an offset + + @param[in] Dest Destiation buffer to copy into + @param[in] uOffset The byte offset in Dest at which to copy to + @param[in] Src The bytes to copy + + @return Pointer and length of the copy + + This fails and returns NULLUsefulBufC Src.len + uOffset > Dest.len. + + Like memcpy, there is no check for NULL. If NULL is passed + this will crash. + + There is an assumption that there is valid data in Dest up to + uOffset as the resulting UsefulBufC returned starts + at the beginning of Dest and goes to Src.len + uOffset. + + */ +UsefulBufC UsefulBuf_CopyOffset(UsefulBuf Dest, size_t uOffset, const UsefulBufC Src); + + +/** + @brief Copy one UsefulBuf into another + + @param[in] Dest The destination buffer to copy into + @param[out] Src The source to copy from + + @return filled in UsefulBufC on success, NULLUsefulBufC on failure + + This fails if Src.len is greater than Dest.len. + + Note that like memcpy, the pointers are not checked and + this will crash, rather than return NULLUsefulBufC if + they are NULL or invalid. + + Results are undefined if Dest and Src overlap. + + */ +static inline UsefulBufC UsefulBuf_Copy(UsefulBuf Dest, const UsefulBufC Src) { + return UsefulBuf_CopyOffset(Dest, 0, Src); +} + + +/** + @brief Set all bytes in a UsefulBuf to a value, for example 0 + + @param[in] pDest The destination buffer to copy into + @param[in] value The value to set the bytes to + + Note that like memset, the pointer in pDest is not checked and + this will crash if NULL or invalid. + + */ +static inline UsefulBufC UsefulBuf_Set(UsefulBuf pDest, uint8_t value) +{ + memset(pDest.ptr, value, pDest.len); + return (UsefulBufC){pDest.ptr, pDest.len}; +} + + +/** + @brief Copy a pointer into a UsefulBuf + + @param[in,out] Dest The destination buffer to copy into + @param[in] ptr The source to copy from + @param[in] len Length of the source; amoutn to copy + + @return 0 on success, 1 on failure + + This fails and returns NULLUsefulBufC if len is greater than + pDest->len. + + Note that like memcpy, the pointers are not checked and + this will crash, rather than return 1 if they are NULL + or invalid. + + */ +inline static UsefulBufC UsefulBuf_CopyPtr(UsefulBuf Dest, const void *ptr, size_t len) +{ + return UsefulBuf_Copy(Dest, (UsefulBufC){ptr, len}); +} + + +/** + @brief Returns a truncation of a UsefulBufC + + @param[in] UB The buffer to get the head of + @param[in] uAmount The number of bytes in the head + + @return A UsefulBufC that is the head of UB + + */ +static inline UsefulBufC UsefulBuf_Head(UsefulBufC UB, size_t uAmount) +{ + if(uAmount > UB.len) { + return NULLUsefulBufC; + } + return (UsefulBufC){UB.ptr, uAmount}; +} + + +/** + @brief Returns bytes from the end of a UsefulBufC + + @param[in] UB The buffer to get the tail of + @param[in] uAmount The offset from the start where the tail is to begin + + @return A UsefulBufC that is the tail of UB or NULLUsefulBufC if + uAmount is greater than the length of the UsefulBufC + + If the input UsefulBufC is NULL, but the len is not, then the + length of the tail will be calculated and returned along + with a NULL ptr. + */ +static inline UsefulBufC UsefulBuf_Tail(UsefulBufC UB, size_t uAmount) +{ + UsefulBufC ReturnValue; + + if(uAmount > UB.len) { + ReturnValue = NULLUsefulBufC; + } else if(UB.ptr == NULL) { + ReturnValue = (UsefulBufC){NULL, UB.len - uAmount}; + } else { + ReturnValue = (UsefulBufC){(uint8_t *)UB.ptr + uAmount, UB.len - uAmount}; + } + + return ReturnValue; +} + + +/** + @brief Compare two UsefulBufCs + + @param[in] UB1 The destination buffer to copy into + @param[in] UB2 The source to copy from + + @return 0 if equal... + + Returns a negative value if UB1 if is less than UB2. UB1 is + less than UB2 if it is shorter or the first byte that is not + the same is less. + + Returns 0 if the UsefulBufs are the same. + + Returns a positive value if UB2 is less than UB1. + + All that is of significance is that the result is positive, + negative or 0. (This doesn't return the difference between + the first non-matching byte like memcmp). + + */ +int UsefulBuf_Compare(const UsefulBufC UB1, const UsefulBufC UB2); + + +/** + @brief Find one UsefulBuf in another + + @param[in] BytesToSearch UsefulBuf to search through + @param[in] BytesToFind UsefulBuf with bytes to be found + + @return position of found bytes or SIZE_MAX if not found. + + */ +size_t UsefulBuf_FindBytes(UsefulBufC BytesToSearch, UsefulBufC BytesToFind); + + + + +#if 0 // NOT_DEPRECATED +/** Deprecated macro; use UsefulBuf_FROM_SZ_LITERAL instead */ +#define SZLiteralToUsefulBufC(szString) \ + ((UsefulBufC) {(szString), sizeof(szString)-1}) + +/** Deprecated macro; use UsefulBuf_MAKE_STACK_UB instead */ +#define MakeUsefulBufOnStack(name, size) \ + uint8_t __pBuf##name[(size)];\ + UsefulBuf name = {__pBuf##name , sizeof( __pBuf##name )} + +/** Deprecated macro; use UsefulBuf_FROM_BYTE_ARRAY_LITERAL instead */ +#define ByteArrayLiteralToUsefulBufC(pBytes) \ + ((UsefulBufC) {(pBytes), sizeof(pBytes)}) + +/** Deprecated function; use UsefulBuf_Unconst() instead */ +static inline UsefulBuf UsefulBufC_Unconst(const UsefulBufC UBC) +{ + return (UsefulBuf){(void *)UBC.ptr, UBC.len}; +} +#endif + + + +/* + Convenient functions to avoid type punning, compiler warnings and such + The optimizer reduces them to a simple assignment + This is a crusty corner of C. It shouldn't be this hard. + */ +static inline uint32_t UsefulBufUtil_CopyFloatToUint32(float f) +{ + uint32_t u32; + memcpy(&u32, &f, sizeof(uint32_t)); + return u32; +} + +static inline uint64_t UsefulBufUtil_CopyDoubleToUint64(double d) +{ + uint64_t u64; + memcpy(&u64, &d, sizeof(uint64_t)); + return u64; +} + +static inline double UsefulBufUtil_CopyUint64ToDouble(uint64_t u64) +{ + double d; + memcpy(&d, &u64, sizeof(uint64_t)); + return d; +} + +static inline float UsefulBufUtil_CopyUint32ToFloat(uint32_t u32) +{ + float f; + memcpy(&f, &u32, sizeof(uint32_t)); + return f; +} + + + + + +/** + UsefulOutBuf is a structure and functions (an object) that are good + for serializing data into a buffer such as is often done with network + protocols or data written to files. + + The main idea is that all the pointer manipulation for adding data is + done by UsefulOutBuf functions so the caller doesn't have to do any. + All the pointer manipulation is centralized here. This code will + have been reviewed and written carefully so it spares the caller of + much of this work and results in much safer code with much less work. + + The functions to add data to the output buffer always check the + length and will never write off the end of the output buffer. If an + attempt to add data that will not fit is made, an internal error flag + will be set and further attempts to add data will not do anything. + + Basically, if you initialized with the correct buffer, there is no + way to ever write off the end of that buffer when calling the Add + and Insert functions here. + + The functions to add data do not return an error. The working model + is that the caller just makes all the calls to add data without any + error checking on each one. The error is instead checked after all the + data is added when the result is to be used. This makes the caller's + code cleaner. + + There is a utility function to get the error status anytime along the + way if the caller wants. There are functions to see how much room is + left and see if some data will fit too, but their use is generally + not necessary. + + The general call flow is like this: + + - Initialize the UsefulOutBuf with the buffer that is to have the + data added. The caller allocates the buffer. It can be heap + or stack or shared memory (or other). + + - Make calls to add data to the output buffer. Insert and append + are both supported. The append and insert calls will never write + off the end of the buffer. + + - When all data is added, check the error status to make sure + everything fit. + + - Get the resulting serialized data either as a UsefulBuf (a + pointer and length) or have it copied to another buffer. + + UsefulOutBuf can be initialized with just a buffer length by passing + NULL as the pointer to the output buffer. This is useful if you want + to go through the whole serialization process to either see if it + will fit into a given buffer or compute the size of the buffer + needed. Pass a very large buffer size when calling Init, if you want + just to compute the size. + + Some inexpensive simple sanity checks are performed before every data + addition to guard against use of an uninitialized or corrupted + UsefulOutBuf. + + This has been used to create a CBOR encoder. The CBOR encoder has + almost no pointer manipulation in it, is much easier to read, and + easier to review. + + A UsefulOutBuf is 27 bytes or 15 bytes on 64- or 32-bit machines so it + can go on the stack or be a C99 function parameter. + */ + +typedef struct useful_out_buf { + UsefulBuf UB; // Memory that is being output to + size_t data_len; // length of the data + uint16_t magic; // Used to detect corruption and lack of initialization + uint8_t err; +} UsefulOutBuf; + + +/** + @brief Initialize and supply the actual output buffer + + @param[out] me The UsefulOutBuf to initialize + @param[in] Storage Buffer to output into + + Intializes the UsefulOutBuf with storage. Sets the current position + to the beginning of the buffer clears the error. + + This must be called before the UsefulOutBuf is used. + */ +void UsefulOutBuf_Init(UsefulOutBuf *me, UsefulBuf Storage); + + + + +/** Convenience marco to make a UsefulOutBuf on the stack and + initialize it with stack buffer + */ +#define UsefulOutBuf_MakeOnStack(name, size) \ + uint8_t __pBuf##name[(size)];\ + UsefulOutBuf name;\ + UsefulOutBuf_Init(&(name), (UsefulBuf){__pBuf##name, (size)}); + + + +/** + @brief Reset a UsefulOutBuf for re use + + @param[in] me Pointer to the UsefulOutBuf + + This sets the amount of data in the output buffer to none and + clears the error state. + + The output buffer is still the same one and size as from the + UsefulOutBuf_Init() call. + + It doesn't zero the data, just resets to 0 bytes of valid data. + */ +static inline void UsefulOutBuf_Reset(UsefulOutBuf *me) +{ + me->data_len = 0; + me->err = 0; +} + + +/** + @brief Returns position of end of data in the UsefulOutBuf + + @param[in] me Pointer to the UsefulOutBuf + + @return position of end of data + + On a freshly initialized UsefulOutBuf with no data added, this will + return 0. After ten bytes have been added, it will return 10 and so + on. + + Generally callers will not need this function for most uses of + UsefulOutBuf. + + */ +static inline size_t UsefulOutBuf_GetEndPosition(UsefulOutBuf *me) +{ + return me->data_len; +} + + +/** + @brief Returns whether any data has been added to the UsefulOutBuf + + @param[in] me Pointer to the UsefulOutBuf + + @return 1 if output position is at start + + */ +static inline int UsefulOutBuf_AtStart(UsefulOutBuf *me) +{ + return 0 == me->data_len; +} + + +/** + @brief Inserts bytes into the UsefulOutBuf + + @param[in] me Pointer to the UsefulOutBuf + @param[in] NewData UsefulBuf with the bytes to insert + @param[in] uPos Index in output buffer at which to insert + + NewData is the pointer and length for the bytes to be added to the + output buffer. There must be room in the output buffer for all of + NewData or an error will occur. + + The insertion point must be between 0 and the current valid data. If + not an error will occur. Appending data to the output buffer is + achieved by inserting at the end of the valid data. This can be + retrieved by calling UsefulOutBuf_GetEndPosition(). + + When insertion is performed, the bytes between the insertion point and + the end of data previously added to the output buffer is slid to the + right to make room for the new data. + + Overlapping buffers are OK. NewData can point to data in the output + buffer. + + If an error occurs an error state is set in the UsefulOutBuf. No + error is returned. All subsequent attempts to add data will do + nothing. + + Call UsefulOutBuf_GetError() to find out if there is an error. This + is usually not needed until all additions of data are complete. + + */ +void UsefulOutBuf_InsertUsefulBuf(UsefulOutBuf *me, UsefulBufC NewData, size_t uPos); + + +/** + @brief Insert a data buffer into the UsefulOutBuf + + @param[in] me Pointer to the UsefulOutBul + @param[in] pBytes Pointer to the bytes to insert + @param[in] uLen Length of the bytes to insert + @param[in] uPos Index in output buffer at which to insert + + See UsefulOutBuf_InsertUsefulBuf() for details. This is the same with + the difference being a pointer and length is passed in rather than an + UsefulBuf. + + */ +static inline void UsefulOutBuf_InsertData(UsefulOutBuf *me, const void *pBytes, size_t uLen, size_t uPos) +{ + UsefulBufC Data = {pBytes, uLen}; + UsefulOutBuf_InsertUsefulBuf(me, Data, uPos); +} + + +/** + @brief Insert a NULL-terminated string into the UsefulOutBuf + + @param[in] me Pointer to the UsefulOutBuf + @param[in] szString string to append + + */ +static inline void UsefulOutBuf_InsertString(UsefulOutBuf *me, const char *szString, size_t uPos) +{ + UsefulOutBuf_InsertUsefulBuf(me, (UsefulBufC){szString, strlen(szString)}, uPos); +} + + +/** + @brief Insert a byte into the UsefulOutBuf + + @param[in] me Pointer to the UsefulOutBul + @param[in] byte Bytes to insert + @param[in] uPos Index in output buffer at which to insert + + See UsefulOutBuf_InsertUsefulBuf() for details. This is the same with + the difference being a single byte is to be inserted. + */ +static inline void UsefulOutBuf_InsertByte(UsefulOutBuf *me, uint8_t byte, size_t uPos) +{ + UsefulOutBuf_InsertData(me, &byte, 1, uPos); +} + + +/** + @brief Insert a 16-bit integer into the UsefulOutBuf + + @param[in] me Pointer to the UsefulOutBul + @param[in] uInteger16 Integer to insert + @param[in] uPos Index in output buffer at which to insert + + See UsefulOutBuf_InsertUsefulBuf() for details. This is the same with + the difference being a single byte is to be inserted. + + The integer will be inserted in network byte order (big endian) + */ +static inline void UsefulOutBuf_InsertUint16(UsefulOutBuf *me, uint16_t uInteger16, size_t uPos) +{ + // Converts native integer format to network byte order (big endian) + uint8_t tmp[2]; + tmp[0] = (uInteger16 & 0xff00) >> 8; + tmp[1] = (uInteger16 & 0xff); + UsefulOutBuf_InsertData(me, tmp, 2, uPos); +} + + +/** + @brief Insert a 32-bit integer into the UsefulOutBuf + + @param[in] me Pointer to the UsefulOutBul + @param[in] uInteger32 Integer to insert + @param[in] uPos Index in output buffer at which to insert + + See UsefulOutBuf_InsertUsefulBuf() for details. This is the same with + the difference being a single byte is to be inserted. + + The integer will be inserted in network byte order (big endian) + */ +static inline void UsefulOutBuf_InsertUint32(UsefulOutBuf *me, uint32_t uInteger32, size_t uPos) +{ + // Converts native integer format to network byte order (big endian) + uint8_t tmp[4]; + tmp[0] = (uInteger32 & 0xff000000) >> 24; + tmp[1] = (uInteger32 & 0xff0000) >> 16; + tmp[2] = (uInteger32 & 0xff00) >> 8; + tmp[3] = (uInteger32 & 0xff); + UsefulOutBuf_InsertData(me, tmp, 4, uPos); +} + + +/** + @brief Insert a 64-bit integer into the UsefulOutBuf + + @param[in] me Pointer to the UsefulOutBul + @param[in] uInteger64 Integer to insert + @param[in] uPos Index in output buffer at which to insert + + See UsefulOutBuf_InsertUsefulBuf() for details. This is the same with + the difference being a single byte is to be inserted. + + The integer will be inserted in network byte order (big endian) + */ +static inline void UsefulOutBuf_InsertUint64(UsefulOutBuf *me, uint64_t uInteger64, size_t uPos) +{ + // Converts native integer format to network byte order (big endian) + uint8_t tmp[8]; + tmp[0] = (uInteger64 & 0xff00000000000000) >> 56; + tmp[1] = (uInteger64 & 0xff000000000000) >> 48; + tmp[2] = (uInteger64 & 0xff0000000000) >> 40; + tmp[3] = (uInteger64 & 0xff00000000) >> 32; + tmp[4] = (uInteger64 & 0xff000000) >> 24; + tmp[5] = (uInteger64 & 0xff0000) >> 16; + tmp[6] = (uInteger64 & 0xff00) >> 8; + tmp[7] = (uInteger64 & 0xff); + UsefulOutBuf_InsertData(me, tmp, 8, uPos); +} + + +/** + @brief Insert a float into the UsefulOutBuf + + @param[in] me Pointer to the UsefulOutBul + @param[in] f Integer to insert + @param[in] uPos Index in output buffer at which to insert + + See UsefulOutBuf_InsertUsefulBuf() for details. This is the same with + the difference being a single byte is to be inserted. + + The float will be inserted in network byte order (big endian) + */ +static inline void UsefulOutBuf_InsertFloat(UsefulOutBuf *me, float f, size_t uPos) +{ + UsefulOutBuf_InsertUint32(me, UsefulBufUtil_CopyFloatToUint32(f), uPos); +} + + +/** + @brief Insert a double into the UsefulOutBuf + + @param[in] me Pointer to the UsefulOutBul + @param[in] d Integer to insert + @param[in] uPos Index in output buffer at which to insert + + See UsefulOutBuf_InsertUsefulBuf() for details. This is the same with + the difference being a single byte is to be inserted. + + The double will be inserted in network byte order (big endian) + */ +static inline void UsefulOutBuf_InsertDouble(UsefulOutBuf *me, double d, size_t uPos) +{ + UsefulOutBuf_InsertUint64(me, UsefulBufUtil_CopyDoubleToUint64(d), uPos); +} + + + +/** + Append a UsefulBuf into the UsefulOutBuf + + @param[in] me Pointer to the UsefulOutBuf + @param[in] NewData UsefulBuf with the bytes to append + + See UsefulOutBuf_InsertUsefulBuf() for details. This does the same + with the insertion point at the end of the valid data. + +*/ +static inline void UsefulOutBuf_AppendUsefulBuf(UsefulOutBuf *me, UsefulBufC NewData) +{ + // An append is just a insert at the end + UsefulOutBuf_InsertUsefulBuf(me, NewData, UsefulOutBuf_GetEndPosition(me)); +} + + +/** + Append bytes to the UsefulOutBuf + + @param[in] me Pointer to the UsefulOutBuf + @param[in] pBytes Pointer to bytes to append + @param[in] uLen Index in output buffer at which to append + + See UsefulOutBuf_InsertUsefulBuf() for details. This does the same + with the insertion point at the end of the valid data. + */ + +static inline void UsefulOutBuf_AppendData(UsefulOutBuf *me, const void *pBytes, size_t uLen) +{ + UsefulBufC Data = {pBytes, uLen}; + UsefulOutBuf_AppendUsefulBuf(me, Data); +} + + +/** + Append a NULL-terminated string to the UsefulOutBuf + + @param[in] me Pointer to the UsefulOutBuf + @param[in] szString string to append + + */ +static inline void UsefulOutBuf_AppendString(UsefulOutBuf *me, const char *szString) +{ + UsefulOutBuf_AppendUsefulBuf(me, (UsefulBufC){szString, strlen(szString)}); +} + + +/** + @brief Append a byte to the UsefulOutBuf + + @param[in] me Pointer to the UsefulOutBuf + @param[in] byte Bytes to append + + See UsefulOutBuf_InsertUsefulBuf() for details. This does the same + with the insertion point at the end of the valid data. + */ +static inline void UsefulOutBuf_AppendByte(UsefulOutBuf *me, uint8_t byte) +{ + UsefulOutBuf_AppendData(me, &byte, 1); +} + +/** + @brief Append an integer to the UsefulOutBuf + + @param[in] me Pointer to the UsefulOutBuf + @param[in] uInteger16 Integer to append + + See UsefulOutBuf_InsertUsefulBuf() for details. This does the same + with the insertion point at the end of the valid data. + + The integer will be appended in network byte order (big endian). + */ +static inline void UsefulOutBuf_AppendUint16(UsefulOutBuf *me, uint16_t uInteger16){ + UsefulOutBuf_InsertUint16(me, uInteger16, UsefulOutBuf_GetEndPosition(me)); +} + +/** + @brief Append an integer to the UsefulOutBuf + + @param[in] me Pointer to the UsefulOutBuf + @param[in] uInteger32 Integer to append + + See UsefulOutBuf_InsertUsefulBuf() for details. This does the same + with the insertion point at the end of the valid data. + + The integer will be appended in network byte order (big endian). + */ +static inline void UsefulOutBuf_AppendUint32(UsefulOutBuf *me, uint32_t uInteger32){ + UsefulOutBuf_InsertUint32(me, uInteger32, UsefulOutBuf_GetEndPosition(me)); +} + +/** + @brief Append an integer to the UsefulOutBuf + + @param[in] me Pointer to the UsefulOutBuf + @param[in] uInteger64 Integer to append + + See UsefulOutBuf_InsertUsefulBuf() for details. This does the same + with the insertion point at the end of the valid data. + + The integer will be appended in network byte order (big endian). + */ +static inline void UsefulOutBuf_AppendUint64(UsefulOutBuf *me, uint64_t uInteger64){ + UsefulOutBuf_InsertUint64(me, uInteger64, UsefulOutBuf_GetEndPosition(me)); +} + + +/** + @brief Append a float to the UsefulOutBuf + + @param[in] me Pointer to the UsefulOutBuf + @param[in] f Float to append + + See UsefulOutBuf_InsertUsefulBuf() for details. This does the same + with the insertion point at the end of the valid data. + + The float will be appended in network byte order (big endian). + */ +static inline void UsefulOutBuf_AppendFloat(UsefulOutBuf *me, float f){ + UsefulOutBuf_InsertFloat(me, f, UsefulOutBuf_GetEndPosition(me)); +} + +/** + @brief Append a float to the UsefulOutBuf + + @param[in] me Pointer to the UsefulOutBuf + @param[in] d Double to append + + See UsefulOutBuf_InsertUsefulBuf() for details. This does the same + with the insertion point at the end of the valid data. + + The double will be appended in network byte order (big endian). + */ +static inline void UsefulOutBuf_AppendDouble(UsefulOutBuf *me, double d){ + UsefulOutBuf_InsertDouble(me, d, UsefulOutBuf_GetEndPosition(me)); +} + +/** + @brief Returns the current error status + + @param[in] me Pointer to the UsefulOutBuf + + @return 0 if all OK, 1 on error + + This is the error status since the call to either + UsefulOutBuf_Reset() of UsefulOutBuf_Init(). Once it goes into error + state it will stay until one of those functions is called. + + Possible error conditions are: + - bytes to be inserted will not fit + - insertion point is out of buffer or past valid data + - current position is off end of buffer (probably corruption or uninitialized) + - detect corruption / uninitialized by bad magic number + */ + +static inline int UsefulOutBuf_GetError(UsefulOutBuf *me) +{ + return me->err; +} + + +/** + @brief Returns number of bytes unused used in the output buffer + + @param[in] me Pointer to the UsefulOutBuf + + @return Number of unused bytes or zero + + Because of the error handling strategy and checks in UsefulOutBuf_InsertUsefulBuf() + it is usually not necessary to use this. + */ + +static inline size_t UsefulOutBuf_RoomLeft(UsefulOutBuf *me) +{ + return me->UB.len - me->data_len; +} + + +/** + @brief Returns true / false if some number of bytes will fit in the UsefulOutBuf + + @param[in] me Pointer to the UsefulOutBuf + @param[in] uLen Number of bytes for which to check + + @return 1 or 0 if nLen bytes would fit + + Because of the error handling strategy and checks in UsefulOutBuf_InsertUsefulBuf() + it is usually not necessary to use this. + */ + +static inline int UsefulOutBuf_WillItFit(UsefulOutBuf *me, size_t uLen) +{ + return uLen <= UsefulOutBuf_RoomLeft(me); +} + + +/** + @brief Returns the resulting valid data in a UsefulOutBuf + + @param[in] me Pointer to the UsefulOutBuf. + + @return The valid data in UsefulOutBuf. + + The storage for the returned data is Storage parameter passed + to UsefulOutBuf_Init(). See also UsefulOutBuf_CopyOut(). + + This can be called anytime and many times to get intermediate + results. It doesn't change the data or reset the current position + so you can keep adding data. + */ + +UsefulBufC UsefulOutBuf_OutUBuf(UsefulOutBuf *me); + + +/** + @brief Copies the valid data out into a supplied buffer + + @param[in] me Pointer to the UsefulOutBuf + @param[out] Dest The destination buffer to copy into + + @return Pointer and length of copied data. + + This is the same as UsefulOutBuf_OutUBuf() except it copies the data. +*/ + +UsefulBufC UsefulOutBuf_CopyOut(UsefulOutBuf *me, UsefulBuf Dest); + + + + + + + + + + + + + +/** + UsefulInputBuf is the counterpart to UsefulOutBuf and is for parsing + data read or received. Initialize it with the data + from the network and its length. Then use the functions + here to get the various data types out of it. It maintains a position + for getting the next item. This means you don't have to track a + pointer as you get each object. UsefulInputBuf does that for you and + makes sure it never goes off the end of the buffer. The QCBOR + implementation parser makes use of this for all its pointer math and + length checking. + + UsefulInputBuf also maintains an internal error state so you do not have + to. Once data has been requested off the end of the buffer, it goes + into an error state. You can keep calling functions to get more data + but they will either return 0 or NULL. As long as you don't + dereference the NULL, you can wait until all data items have been + fetched before checking for the error and this can simplify your + code. + + The integer and float parsing expects network byte order (big endian). + Network byte order is what is used by TCP/IP, CBOR and most internet + protocols. + + Lots of inlining is used to keep code size down. The code optimizer, + particularly with the -Os, also reduces code size a lot. The only + non-inline code is UsefulInputBuf_GetBytes() which is less than 100 + bytes so use of UsefulInputBuf doesn't add much code for all the messy + hard-to-get right issues with parsing in C that is solves. + + The parse context size is: + 64-bit machine: 16 + 8 + 2 + 1 (5 bytes padding to align) = 32 bytes + 32-bit machine: 8 + 4 + 2 + 1 (1 byte padding to align) = 16 bytes + + */ + +#define UIB_MAGIC (0xB00F) + +typedef struct useful_input_buf { + // Private data structure + UsefulBufC UB; // Data being parsed + size_t cursor; // Current offset in data being parse + uint16_t magic; // Check for corrupted or uninitialized UsefulInputBuf + uint8_t err; // Set request goes off end or magic number is bad +} UsefulInputBuf; + + + +/** + @brief Initialize the UsefulInputBuf structure before use. + + @param[in] me Pointer to the UsefulInputBuf instance. + @param[in] UB Pointer to the data to parse. + + */ +static inline void UsefulInputBuf_Init(UsefulInputBuf *me, UsefulBufC UB) +{ + me->cursor = 0; + me->err = 0; + me->magic = UIB_MAGIC; + me->UB = UB; +} + + +/** + @brief Returns current position in input buffer + + @param[in] me Pointer to the UsefulInputBuf. + + @return Integer position of the cursor + + The position that the next bytes will be returned from. + + */ +static inline size_t UsefulInputBuf_Tell(UsefulInputBuf *me) +{ + return me->cursor; +} + + +/** + @brief Sets current position in input buffer + + @param[in] me Pointer to the UsefulInputBuf. + @param[in] uPos Position to set to + + If the position is off the end of the input buffer, the error state + is entered and all functions will do nothing. + + Seeking to a valid position in the buffer will not reset the error + state. Only re initialization will do that. + + */ +static inline void UsefulInputBuf_Seek(UsefulInputBuf *me, size_t uPos) +{ + if(uPos > me->UB.len) { + me->err = 1; + } else { + me->cursor = uPos; + } +} + + +/** + @brief Returns the number of bytes from the cursor to the end of the buffer, + the uncomsummed bytes. + + @param[in] me Pointer to the UsefulInputBuf. + + @return number of bytes unconsumed or 0 on error. + + This is a critical function for input length validation. This does + some pointer / offset math. + + Returns 0 if the cursor it invalid or corruption of the structure is + detected. + + Code Reviewers: THIS FUNCTION DOES POINTER MATH + */ +static inline size_t UsefulInputBuf_BytesUnconsumed(UsefulInputBuf *me) +{ + // Magic number is messed up. Either the structure got overwritten + // or was never initialized. + if(me->magic != UIB_MAGIC) { + return 0; + } + + // The cursor is off the end of the input buffer given + // Presuming there are no bugs in this code, this should never happen. + // If it so, the struct was corrupted. The check is retained as + // as a defense in case there is a bug in this code or the struct is corrupted. + if(me->cursor > me->UB.len) { + return 0; + } + + // subtraction can't go neative because of check above + return me->UB.len - me->cursor; +} + + +/** + @brief Check if there are any unconsumed bytes + + @param[in] me Pointer to the UsefulInputBuf. + + @return 1 if len bytes are available after the cursor, and 0 if not + + */ +static inline int UsefulInputBuf_BytesAvailable(UsefulInputBuf *me, size_t uLen) +{ + return UsefulInputBuf_BytesUnconsumed(me) >= uLen ? 1 : 0; +} + + +/** + @brief Get pointer to bytes out of the input buffer + + @param[in] me Pointer to the UsefulInputBuf. + @param[in] uNum Number of bytes to get + + @return Pointer to bytes. + + This consumes n bytes from the input buffer. It returns a pointer to + the start of the n bytes. + + If there are not n bytes in the input buffer, NULL will be returned + and an error will be set. + + It advances the current position by n bytes. + */ +const void * UsefulInputBuf_GetBytes(UsefulInputBuf *me, size_t uNum); + + +/** + @brief Get UsefulBuf out of the input buffer + + @param[in] me Pointer to the UsefulInputBuf. + @param[in] uNum Number of bytes to get + + @return UsefulBufC with ptr and length for bytes consumed. + + This consumes n bytes from the input buffer and returns the pointer + and len to them as a UsefulBufC. The len returned will always be n. + + If there are not n bytes in the input buffer, UsefulBufC.ptr will be + NULL and UsefulBufC.len will be 0. An error will be set. + + It advances the current position by n bytes. + */ +static inline UsefulBufC UsefulInputBuf_GetUsefulBuf(UsefulInputBuf *me, size_t uNum) +{ + const void *pResult = UsefulInputBuf_GetBytes(me, uNum); + if(!pResult) { + return NULLUsefulBufC; + } else { + return (UsefulBufC){pResult, uNum}; + } +} + + +/** + @brief Get a byte out of the input buffer. + + @param[in] me Pointer to the UsefulInputBuf. + + @return The byte + + This consumes 1 byte from the input buffer. It returns the byte. + + If there is not 1 byte in the buffer, 0 will be returned for the byte + and an error set internally. You must check the error at some point + to know whether the 0 was the real value or just returned in error, + but you may not have to do that right away. Check the error state + with UsefulInputBuf_GetError(). You can also know you are in the + error state if UsefulInputBuf_GetBytes() returns NULL or the ptr from + UsefulInputBuf_GetUsefulBuf() is NULL. + + It advances the current position by 1 byte. + */ +static inline uint8_t UsefulInputBuf_GetByte(UsefulInputBuf *me) +{ + const void *pResult = UsefulInputBuf_GetBytes(me, sizeof(uint8_t)); + + return pResult ? *(uint8_t *)pResult : 0; +} + + +/** + @brief Get a uint16_t out of the input buffer + + @param[in] me Pointer to the UsefulInputBuf. + + @return The uint16_t + + See UsefulInputBuf_GetByte(). This works the same, except it returns + a uint16_t and two bytes are consumed. + + The input bytes must be in network order (big endian). + */ +static inline uint16_t UsefulInputBuf_GetUint16(UsefulInputBuf *me) +{ + const uint8_t *pResult = (const uint8_t *)UsefulInputBuf_GetBytes(me, sizeof(uint16_t)); + + if(!pResult) { + return 0; + } + + return ((uint16_t)pResult[0] << 8) + (uint16_t)pResult[1]; +} + + +/** + @brief Get a uint32_t out of the input buffer + + @param[in] me Pointer to the UsefulInputBuf. + + @return The uint32_t + + See UsefulInputBuf_GetByte(). This works the same, except it returns + a uint32_t and four bytes are consumed. + + The input bytes must be in network order (big endian). + */ +static inline uint32_t UsefulInputBuf_GetUint32(UsefulInputBuf *me) +{ + const uint8_t *pResult = (const uint8_t *)UsefulInputBuf_GetBytes(me, sizeof(uint32_t)); + + if(!pResult) { + return 0; + } + + return ((uint32_t)pResult[0]<<24) + + ((uint32_t)pResult[1]<<16) + + ((uint32_t)pResult[2]<<8) + + (uint32_t)pResult[3]; +} + + +/** + @brief Get a uint64_t out of the input buffer + + @param[in] me Pointer to the UsefulInputBuf. + + @return The uint64_t + + See UsefulInputBuf_GetByte(). This works the same, except it returns + a uint64_t and eight bytes are consumed. + + The input bytes must be in network order (big endian). + */ +static inline uint64_t UsefulInputBuf_GetUint64(UsefulInputBuf *me) +{ + const uint8_t *pResult = (const uint8_t *)UsefulInputBuf_GetBytes(me, sizeof(uint64_t)); + + if(!pResult) { + return 0; + } + + return ((uint64_t)pResult[0]<<56) + + ((uint64_t)pResult[1]<<48) + + ((uint64_t)pResult[2]<<40) + + ((uint64_t)pResult[3]<<32) + + ((uint64_t)pResult[4]<<24) + + ((uint64_t)pResult[5]<<16) + + ((uint64_t)pResult[6]<<8) + + (uint64_t)pResult[7]; +} + + +/** + @brief Get a float out of the input buffer + + @param[in] me Pointer to the UsefulInputBuf. + + @return The float + + See UsefulInputBuf_GetByte(). This works the same, except it returns + a float and four bytes are consumed. + + The input bytes must be in network order (big endian). + */ +static inline float UsefulInputBuf_GetFloat(UsefulInputBuf *me) +{ + uint32_t uResult = UsefulInputBuf_GetUint32(me); + + return uResult ? UsefulBufUtil_CopyUint32ToFloat(uResult) : 0; +} + +/** + @brief Get a double out of the input buffer + + @param[in] me Pointer to the UsefulInputBuf. + + @return The double + + See UsefulInputBuf_GetByte(). This works the same, except it returns + a double and eight bytes are consumed. + + The input bytes must be in network order (big endian). + */ +static inline double UsefulInputBuf_GetDouble(UsefulInputBuf *me) +{ + uint64_t uResult = UsefulInputBuf_GetUint64(me); + + return uResult ? UsefulBufUtil_CopyUint64ToDouble(uResult) : 0; +} + + +/** + @brief Get the error status + + @param[in] me Pointer to the UsefulInputBuf. + + @return The error. + + Zero is success, non-zero is error. Once in the error state, the only + way to clear it is to call Init again. + + You may be able to only check the error state at the end after all + the Get()'s have been done, but if what you get later depends on what + you get sooner you cannot. For example if you get a length or count + of following items you will have to check the error. + + */ +static inline int UsefulInputBuf_GetError(UsefulInputBuf *me) +{ + return me->err; +} + + +#endif // _UsefulBuf_h + + diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/qcbor/inc/qcbor.h b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/qcbor/inc/qcbor.h new file mode 100644 index 0000000..f050988 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/qcbor/inc/qcbor.h @@ -0,0 +1,2598 @@ +/*============================================================================== + Copyright (c) 2016-2018, The Linux Foundation. + Copyright (c) 2018-2019, Laurence Lundblade. + All rights reserved. + SPDX-License-Identifier: BSD-3-Clause + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of The Linux Foundation nor the names of its + contributors, nor the name "Laurence Lundblade" may be used to + endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ==============================================================================*/ + + +/*=================================================================================== + FILE: qcbor.h + + DESCRIPTION: This is the full public API and data structures for QCBOR + + EDIT HISTORY FOR FILE: + + This section contains comments describing changes made to the module. + Notice that changes are listed in reverse chronological order. + + when who what, where, why + -------- ---- --------------------------------------------------- + 12/18/18 llundblade Move decode malloc optional code to separate repository + 12/13/18 llundblade Documentatation improvements + 11/29/18 llundblade Rework to simpler handling of tags and labels. + 11/9/18 llundblade Error codes are now enums. + 11/1/18 llundblade Floating support. + 10/31/18 llundblade Switch to one license that is almost BSD-3. + 10/15/18 llundblade Indefinite length maps and arrays supported + 10/8/18 llundblade Indefinite length strings supported + 09/28/18 llundblade Added bstr wrapping feature for COSE implementation. + 07/05/17 llundbla Add bstr wrapping of maps/arrays for COSE. + 03/01/17 llundbla More data types; decoding improvements and fixes. + 11/13/16 llundbla Integrate most TZ changes back into github version. + 09/30/16 gkanike Porting to TZ. + 03/15/16 llundbla Initial Version. + + =====================================================================================*/ + +#ifndef __QCBOR__qcbor__ +#define __QCBOR__qcbor__ + +/*...... This is a ruler that is 80 characters long...........................*/ + +/* =========================================================================== + BEGINNING OF PRIVATE PART OF THIS FILE + + Caller of QCBOR should not reference any of the details below up until + the start of the public part. + =========================================================================== */ + +/* + Standard integer types are used in the interface to be precise about + sizes to be better at preventing underflow/overflow errors. + */ +#include +#include +#include "UsefulBuf.h" + + +/* + The maxium nesting of arrays and maps when encoding or decoding. + (Further down in the file there is a definition that refers to this + that is public. This is done this way so there can be a nice + separation of public and private parts in this file. +*/ +#define QCBOR_MAX_ARRAY_NESTING1 15 // Do not increase this over 255 + + +/* The largest offset to the start of an array or map. It is slightly + less than UINT32_MAX so the error condition can be tests on 32-bit machines. + UINT32_MAX comes from uStart in QCBORTrackNesting being a uin32_t. + + This will cause trouble on a machine where size_t is less than 32-bits. + */ +#define QCBOR_MAX_ARRAY_OFFSET (UINT32_MAX - 100) + +/* + PRIVATE DATA STRUCTURE + + Holds the data for tracking array and map nesting during encoding. Pairs up with + the Nesting_xxx functions to make an "object" to handle nesting encoding. + + uStart is a uint32_t instead of a size_t to keep the size of this + struct down so it can be on the stack without any concern. It would be about + double if size_t was used instead. + + Size approximation (varies with CPU/compiler): + 64-bit machine: (15 + 1) * (4 + 2 + 1 + 1 pad) + 8 = 136 bytes + 32-bit machine: (15 + 1) * (4 + 2 + 1 + 1 pad) + 4 = 132 bytes +*/ +typedef struct __QCBORTrackNesting { + // PRIVATE DATA STRUCTURE + struct { + // See function OpenArrayInternal() for detailed comments on how this works + uint32_t uStart; // uStart is the byte position where the array starts + uint16_t uCount; // Number of items in the arrary or map; counts items in a map, not pairs of items + uint8_t uMajorType; // Indicates if item is a map or an array + } pArrays[QCBOR_MAX_ARRAY_NESTING1+1], // stored state for the nesting levels + *pCurrentNesting; // the current nesting level +} QCBORTrackNesting; + + +/* + PRIVATE DATA STRUCTURE + + Context / data object for encoding some CBOR. Used by all encode functions to + form a public "object" that does the job of encdoing. + + Size approximation (varies with CPU/compiler): + 64-bit machine: 27 + 1 (+ 4 padding) + 136 = 32 + 136 = 168 bytes + 32-bit machine: 15 + 1 + 132 = 148 bytes +*/ +struct _QCBOREncodeContext { + // PRIVATE DATA STRUCTURE + UsefulOutBuf OutBuf; // Pointer to output buffer, its length and position in it + uint8_t uError; // Error state + QCBORTrackNesting nesting; // Keep track of array and map nesting +}; + + +/* + PRIVATE DATA STRUCTURE + + Holds the data for array and map nesting for decoding work. This structure + and the DecodeNesting_xxx functions form an "object" that does the work + for arrays and maps. + + Size approximation (varies with CPU/compiler): + 64-bit machine: 4 * 16 + 8 = 72 + 32-bit machine: 4 * 16 + 4 = 68 + */ +typedef struct __QCBORDecodeNesting { + // PRIVATE DATA STRUCTURE + struct { + uint16_t uCount; + uint8_t uMajorType; + } pMapsAndArrays[QCBOR_MAX_ARRAY_NESTING1+1], + *pCurrent; +} QCBORDecodeNesting; + + +/* + PRIVATE DATA STRUCTURE + + The decode context. This data structure plus the public QCBORDecode_xxx + functions form an "object" that does CBOR decoding. + + Size approximation (varies with CPU/compiler): + 64-bit machine: 32 + 1 + 1 + 6 bytes padding + 72 + 16 = 128 bytes + 32-bit machine: 16 + 1 + 1 + 2 bytes padding + 68 + 8 = 68 bytes + */ +struct _QCBORDecodeContext { + // PRIVATE DATA STRUCTURE + UsefulInputBuf InBuf; + + uint8_t uDecodeMode; + uint8_t bStringAllocateAll; + + QCBORDecodeNesting nesting; + + // This is NULL or points to a QCBORStringAllocator. It is void + // here because _QCBORDecodeContext is defined early in the + // private part of this file and QCBORStringAllocat is defined + // later in the public part of this file. + void *pStringAllocator; + + // This is NULL or points to QCBORTagList. + // It is type void for the same reason as above. + const void *pCallerConfiguredTagList; +}; + +// Used internally in the impementation here +// Must not conflict with any of the official CBOR types +#define CBOR_MAJOR_NONE_TYPE_RAW 9 +#define CBOR_MAJOR_NONE_TAG_LABEL_REORDER 10 + + +/* =========================================================================== + END OF PRIVATE PART OF THIS FILE + + BEGINNING OF PUBLIC PART OF THIS FILE + =========================================================================== */ + + + +/* =========================================================================== + BEGINNING OF CONSTANTS THAT COME FROM THE CBOR STANDARD, RFC 7049 + + It is not necessary to use these directly when encoding or decoding + CBOR with this implementation. + =========================================================================== */ + +/* Standard CBOR Major type for positive integers of various lengths */ +#define CBOR_MAJOR_TYPE_POSITIVE_INT 0 + +/* Standard CBOR Major type for negative integer of various lengths */ +#define CBOR_MAJOR_TYPE_NEGATIVE_INT 1 + +/* Standard CBOR Major type for an array of arbitrary 8-bit bytes. */ +#define CBOR_MAJOR_TYPE_BYTE_STRING 2 + +/* Standard CBOR Major type for a UTF-8 string. Note this is true 8-bit UTF8 + with no encoding and no NULL termination */ +#define CBOR_MAJOR_TYPE_TEXT_STRING 3 + +/* Standard CBOR Major type for an ordered array of other CBOR data items */ +#define CBOR_MAJOR_TYPE_ARRAY 4 + +/* Standard CBOR Major type for CBOR MAP. Maps an array of pairs. The + first item in the pair is the "label" (key, name or identfier) and the second + item is the value. */ +#define CBOR_MAJOR_TYPE_MAP 5 + +/* Standard CBOR optional tagging. This tags things like dates and URLs */ +#define CBOR_MAJOR_TYPE_OPTIONAL 6 + +/* Standard CBOR extra simple types like floats and the values true and false */ +#define CBOR_MAJOR_TYPE_SIMPLE 7 + + +/* + These are special values for the AdditionalInfo bits that are part of the first byte. + Mostly they encode the length of the data item. + */ +#define LEN_IS_ONE_BYTE 24 +#define LEN_IS_TWO_BYTES 25 +#define LEN_IS_FOUR_BYTES 26 +#define LEN_IS_EIGHT_BYTES 27 +#define ADDINFO_RESERVED1 28 +#define ADDINFO_RESERVED2 29 +#define ADDINFO_RESERVED3 30 +#define LEN_IS_INDEFINITE 31 + + +/* + 24 is a special number for CBOR. Integers and lengths + less than it are encoded in the same byte as the major type + */ +#define CBOR_TWENTY_FOUR 24 + + +/* + Tags that are used with CBOR_MAJOR_TYPE_OPTIONAL. These are + the ones defined in the CBOR spec. + */ +/** See QCBOREncode_AddDateString() below */ +#define CBOR_TAG_DATE_STRING 0 +/** See QCBOREncode_AddDateEpoch_2() */ +#define CBOR_TAG_DATE_EPOCH 1 +#define CBOR_TAG_POS_BIGNUM 2 +#define CBOR_TAG_NEG_BIGNUM 3 +#define CBOR_TAG_FRACTION 4 +#define CBOR_TAG_BIGFLOAT 5 + +#define CBOR_TAG_COSE_ENCRYPTO 16 +#define CBOR_TAG_COSE_MAC0 17 +#define CBOR_TAG_COSE_SIGN1 18 + +/* The data in byte string should be converted in base 64 URL when encoding in JSON or similar text-based representations */ +#define CBOR_TAG_ENC_AS_B64URL 21 +/* The data in byte string should be encoded in base 64 when encoding in JSON */ +#define CBOR_TAG_ENC_AS_B64 22 +/* The data in byte string should be encoded in base 16 when encoding in JSON */ +#define CBOR_TAG_ENC_AS_B16 23 +#define CBOR_TAG_CBOR 24 +/** The data in the string is a URIs, as defined in RFC3986 */ +#define CBOR_TAG_URI 32 +/** The data in the string is a base 64'd URL */ +#define CBOR_TAG_B64URL 33 +/** The data in the string is base 64'd */ +#define CBOR_TAG_B64 34 +/** regular expressions in Perl Compatible Regular Expressions (PCRE) / JavaScript syntax ECMA262. */ +#define CBOR_TAG_REGEX 35 +/** MIME messages (including all headers), as defined in RFC2045 */ +#define CBOR_TAG_MIME 36 +/** Binary UUID */ +#define CBOR_TAG_BIN_UUID 37 + +#define CBOR_TAG_CWT 61 + +#define CBOR_TAG_ENCRYPT 96 +#define CBOR_TAG_MAC 97 +#define CBOR_TAG_SIGN 98 + +#define CBOR_TAG_GEO_COORD 103 + + +/** The data is CBOR data */ +#define CBOR_TAG_CBOR_MAGIC 55799 +#define CBOR_TAG_NONE UINT64_MAX + + +/* + Values for the 5 bits for items of major type 7 + */ +#define CBOR_SIMPLEV_FALSE 20 +#define CBOR_SIMPLEV_TRUE 21 +#define CBOR_SIMPLEV_NULL 22 +#define CBOR_SIMPLEV_UNDEF 23 +#define CBOR_SIMPLEV_ONEBYTE 24 +#define HALF_PREC_FLOAT 25 +#define SINGLE_PREC_FLOAT 26 +#define DOUBLE_PREC_FLOAT 27 +#define CBOR_SIMPLE_BREAK 31 + + + +/* =========================================================================== + + END OF CONSTANTS THAT COME FROM THE CBOR STANDARD, RFC 7049 + + BEGINNING OF PUBLIC INTERFACE FOR QCBOR ENCODER / DECODER + + =========================================================================== */ + +/** + + @file qcbor.h + + Q C B O R E n c o d e / D e c o d e + + This implements CBOR -- Concise Binary Object Representation as defined + in RFC 7049. More info is at http://cbor.io. This is a near-complete + implementation of the specification. Limitations are listed further down. + + CBOR is intentionally designed to be translatable to JSON, but not + all CBOR can convert to JSON. See RFC 7049 for more info on how to + construct CBOR that is the most JSON friendly. + + The memory model for encoding and decoding is that encoded CBOR + must be in a contiguous buffer in memory. During encoding the + caller must supply an output buffer and if the encoding would go + off the end of the buffer an error is returned. During decoding + the caller supplies the encoded CBOR in a contiguous buffer + and the decoder returns pointers and lengths into that buffer + for strings. + + This implementation does not require malloc. All data structures + passed in/out of the APIs can fit on the stack. + + Decoding of indefinite length strings is a special case that requires + a "string allocator" to allocate memory into which the segments of + the string are coalesced. Without this, decoding will error out if + an indefinite length string is encountered (indefinite length maps + and arrays do not require the string allocator). A simple string + allocator called MemPool is built-in and will work if supplied with + a block of memory to allocate. The string allocator can optionally + use malloc() or some other custom scheme. + + Here are some terms and definitions: + + - "Item", "Data Item": An integer or string or such. The basic "thing" that + CBOR is about. An array is an item itself that contains some items. + + - "Array": An ordered sequence of items, the same as JSON. + + - "Map": A collection of label/value pairs. Each pair is a data + item. A JSON "object" is the same as a CBOR "map". + + - "Label": The data item in a pair in a map that names or identifies the + pair, not the value. This implementation refers to it as a "label". + JSON refers to it as the "name". The CBOR RFC refers to it this as a "key". + This implementation chooses label instead because key is too easily confused + with a cryptographic key. The COSE standard, which uses CBOR, has also + chosen to use the term "label" rather than "key" for this same reason. + + - "Key": See "Label" above. + + - "Tag": Optional info that can be added before each data item. This is always + CBOR major type 6. + + - "Initial Byte": The first byte of an encoded item. Encoding and decoding of + this byte is taken care of by the implementation. + + - "Additional Info": In addition to the major type, all data items have some + other info. This is usually the length of the data, but can be several + other things. Encoding and decoding of this is taken care of by the + implementation. + + CBOR has two mechanisms for tagging and labeling the data + values like integers and strings. For example, an integer that + represents someone's birthday in epoch seconds since Jan 1, 1970 + could be encoded like this: + + - First it is CBOR_MAJOR_TYPE_POSITIVE_INT, the primitive positive + integer. + - Next it has a "tag" CBOR_TAG_DATE_EPOCH indicating the integer + represents a date in the form of the number of seconds since + Jan 1, 1970. + - Last it has a string "label" like "BirthDate" indicating + the meaning of the data. + + The encoded binary looks like this: + a1 # Map of 1 item + 69 # Indicates text string of 9 bytes + 426972746844617465 # The text "BirthDate" + c1 # Tags next int as epoch date + 1a # Indicates 4 byte integer + 580d4172 # unsigned integer date 1477263730 + + Implementors using this API will primarily work with labels. Generally + tags are only needed for making up new data types. This implementation + covers most of the data types defined in the RFC using tags. It also, + allows for the creation of news tags if necessary. + + This implementation explicitly supports labels that are text strings + and integers. Text strings translate nicely into JSON objects and + are very readable. Integer labels are much less readable, but + can be very compact. If they are in the range of -23 to + 23 they take up only one byte. + + CBOR allows a label to be any type of data including an array or + a map. It is possible to use this API to construct and + parse such labels, but it is not explicitly supported. + + A common encoding usage mode is to invoke the encoding twice. First + with no output buffer to compute the length of the needed output + buffer. Then the correct sized output buffer is allocated. Last the + encoder is invoked again, this time with the output buffer. + + The double invocation is not required if the max output buffer size + can be predicted. This is usually possible for simple CBOR structures. + If the double invocation is implemented, it can be + in a loop or function as in the example code so that the code doesn't + have to actually be written twice, saving code size. + + If a buffer too small to hold the encoded output is given, the error + QCBOR_ERR_BUFFER_TOO_SMALL will be returned. Data will never be + written off the end of the output buffer no matter which functions + here are called or what parameters are passed to them. + + The error handling is simple. The only possible errors are trying to + encode structures that are too large or too complex. There are no + internal malloc calls so there will be no failures for out of memory. + Only the final call, QCBOREncode_Finish(), returns an error code. + Once an error happens, the encoder goes into an error state and calls + to it will do nothing so the encoding can just go on. An error + check is not needed after every data item is added. + + Encoding generally proceeds by calling QCBOREncode_Init(), calling + lots of "Add" functions and calling QCBOREncode_Finish(). There + are many "Add" functions for various data types. The input + buffers need only to be valid during the "Add" calls. The + data is copied into the output buf during the "Add" call. + + There are three `Add` functions for each data type. The first + / main one for the type is for adding the data item to an array. + The second one's name ends in `ToMap`, is used for adding + data items to maps and takes a string + argument that is its label in the map. The third one ends in + `ToMapN`, is also used for adding data items to maps, and + takes an integer argument that is its label in the map. + + The simplest aggregate type is an array, which is a simple ordered + set of items without labels the same as JSON arrays. Call + QCBOREncode_OpenArray() to open a new array, then "Add" to + put items in the array and then QCBOREncode_CloseArray(). Nesting + to a limit is allowed. All opens must be matched by closes or an + encoding error will be returned. + + The other aggregate type is a map which does use labels. The + `Add` functions that end in `ToMap` and `ToMapN` are convenient + ways to add labeled data items to a map. You can also call + any type of `Add` function once to add a label of any time and + then call any type of `Add` again to add its value. + + Note that when you nest arrays or maps in a map, the nested + array or map has a label. + + Usually it is not necessary to add tags explicitly as most + tagged types have functions here, but they can be added by + calling QCBOREncode_AddTag(). There is an IANA registry for new tags that are + for broad use and standardization as per RFC 7049. It is also + allowed for protocols to make up new tags in the range above 256. + Note that even arrays and maps can be tagged. + + Summary Limits of this implementation: + - The entire encoded CBOR must fit into contiguous memory. + - Max size of encoded / decoded CBOR data is UINT32_MAX (4GB). + - Max array / map nesting level when encoding / decoding is + QCBOR_MAX_ARRAY_NESTING (this is typically 15). + - Max items in an array or map when encoding / decoding is + QCBOR_MAX_ITEMS_IN_ARRAY (typically 65,536). + - Does not support encoding indefinite lengths (decoding is supported). + - Does not directly support some tagged types: decimal fractions, big floats + - Does not directly support labels in maps other than text strings and ints. + - Does not directly support int labels greater than INT64_MAX + - Epoch dates limited to INT64_MAX (+/- 292 billion years) + - Tags on labels are ignored during decoding + + This implementation is intended to run on 32 and 64-bit CPUs. Minor + modifications are needed for it to work on 16-bit CPUs. + + The public interface uses size_t for all lengths. Internally the + implementation uses 32-bit lengths by design to use less memory and + fit structures on the stack. This limits the encoded + CBOR it can work with to size UINT32_MAX (4GB) which should be + enough. + + This implementation assumes two's compliment integer + machines. Stdint.h also requires this. It of course would be easy to + fix this implementation for another integer representation, but all + modern machines seem to be two's compliment. + + */ + + +/** + The maximum number of items in a single array or map when encoding of decoding. +*/ +// -1 is because the value UINT16_MAX is used to track indefinite length arraysUINT16_MAX +#define QCBOR_MAX_ITEMS_IN_ARRAY (UINT16_MAX-1) + +/** + The maximum nesting of arrays and maps when encoding or decoding. The + error QCBOR_ERR_ARRAY_NESTING_TOO_DEEP will be returned on encoding + of decoding if it is exceeded +*/ +#define QCBOR_MAX_ARRAY_NESTING QCBOR_MAX_ARRAY_NESTING1 + +/** + The maximum number of tags that can be in QCBORTagListIn and passed to + QCBORDecode_SetCallerConfiguredTagList() + */ +#define QCBOR_MAX_CUSTOM_TAGS 16 + + +typedef enum { + /** The encode or decode completely correctly. */ + QCBOR_SUCCESS = 0, + + /** The buffer provided for the encoded output when doing encoding was + too small and the encoded output will not fit. Also, when the buffer + given to QCBORDecode_SetMemPool() is too small. */ + QCBOR_ERR_BUFFER_TOO_SMALL, + + /** During encoding or decoding, the array or map nesting was deeper than + this implementation can handle. Note that in the interest of code size + and memory use, this implementation has a hard limit on array nesting. The + limit is defined as the constant QCBOR_MAX_ARRAY_NESTING. */ + QCBOR_ERR_ARRAY_NESTING_TOO_DEEP, + + /** During decoding or encoding, the array or map had too many items in it. + This limit QCBOR_MAX_ITEMS_IN_ARRAY, typically 65,535. */ + QCBOR_ERR_ARRAY_TOO_LONG, + + /** During encoding, more arrays or maps were closed than opened. This is a + coding error on the part of the caller of the encoder. */ + QCBOR_ERR_TOO_MANY_CLOSES, + + /** During decoding, some CBOR construct was encountered that this decoder + doesn't support, primarily this is the reserved additional info values, + 28 through 30. */ + QCBOR_ERR_UNSUPPORTED, + + /** During decoding, hit the end of the given data to decode. For example, + a byte string of 100 bytes was expected, but the end of the input was + hit before finding those 100 bytes. Corrupted CBOR input will often + result in this error. */ + QCBOR_ERR_HIT_END, + + /** During encoding, the length of the encoded CBOR exceeded UINT32_MAX. + */ + QCBOR_ERR_BUFFER_TOO_LARGE, + + /** During decoding, an integer smaller than INT64_MIN was received (CBOR + can represent integers smaller than INT64_MIN, but C cannot). */ + QCBOR_ERR_INT_OVERFLOW, + + /** During decoding, the label for a map entry is bad. What causes this + error depends on the decoding mode. */ + QCBOR_ERR_MAP_LABEL_TYPE, + + /** During encoding or decoding, the number of array or map opens was not + matched by the number of closes. */ + QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN, + + /** During encoding, the simple value is not between CBOR_SIMPLEV_FALSE + and CBOR_SIMPLEV_UNDEF. */ + QCBOR_ERR_BAD_SIMPLE, + + /** During decoding, a date greater than +- 292 billion years from Jan 1 + 1970 encountered during parsing. */ + QCBOR_ERR_DATE_OVERFLOW, + + /** During decoding, the CBOR is not valid, primarily a simple type is encoded in + a prohibited way. */ + QCBOR_ERR_INVALID_CBOR, + + /** Optional tagging that doesn't make sense (an int is tagged as a + date string) or can't be handled. */ + QCBOR_ERR_BAD_OPT_TAG, + + /** Returned by QCBORDecode_Finish() if all the inputs bytes have not + been consumed. */ + QCBOR_ERR_EXTRA_BYTES, + + /** During encoding, QCBOREncode_Close() call with a different type than + is currently open. */ + QCBOR_ERR_CLOSE_MISMATCH, + + /** Unable to decode an indefinite length string because no string + allocator was configured. */ + QCBOR_ERR_NO_STRING_ALLOCATOR, + + /** One of the chunks in an indefinite length string is not of the type of + the string. */ + QCBOR_ERR_INDEFINITE_STRING_CHUNK, + + /** Error allocating space for a string, usually for an indefinite length + string. */ + QCBOR_ERR_STRING_ALLOCATE, + + /** During decoding, a break occurred outside an indefinite length item. */ + QCBOR_ERR_BAD_BREAK, + + /** During decoding, too many tags in the caller-configured tag list, or not + enough space in QCBORTagListOut. */ + QCBOR_ERR_TOO_MANY_TAGS, + + /** Returned by QCBORDecode_SetMemPool() when xx is too small. This should + never happen on a machine with 64-bit or smaller pointers. Fixing + it is probably by increasing QCBOR_DECODE_MIN_MEM_POOL_SIZE. */ + QCBOR_ERR_MEM_POOL_INTERNAL + +} QCBORError; + + +typedef enum { + /** See QCBORDecode_Init() */ + QCBOR_DECODE_MODE_NORMAL = 0, + /** See QCBORDecode_Init() */ + QCBOR_DECODE_MODE_MAP_STRINGS_ONLY = 1, + /** See QCBORDecode_Init() */ + QCBOR_DECODE_MODE_MAP_AS_ARRAY = 2 +} QCBORDecodeMode; + + + + + +/* Do not renumber these. Code depends on some of these values. */ +/** The type is unknown, unset or invalid */ +#define QCBOR_TYPE_NONE 0 +/** Type for an integer that decoded either between INT64_MIN and INT32_MIN or INT32_MAX and INT64_MAX; val.int64 */ +#define QCBOR_TYPE_INT64 2 +/** Type for an integer that decoded to a more than INT64_MAX and UINT64_MAX; val.uint64 */ +#define QCBOR_TYPE_UINT64 3 +/** Type for an array. The number of items in the array is in val.uCount. */ +#define QCBOR_TYPE_ARRAY 4 +/** Type for a map; number of items in map is in val.uCount */ +#define QCBOR_TYPE_MAP 5 +/** Type for a buffer full of bytes. Data is in val.string. */ +#define QCBOR_TYPE_BYTE_STRING 6 +/** Type for a UTF-8 string. It is not NULL terminated. Data is in val.string. */ +#define QCBOR_TYPE_TEXT_STRING 7 +/** Type for a positive big number. Data is in val.bignum, a pointer and a length. */ +#define QCBOR_TYPE_POSBIGNUM 9 +/** Type for a negative big number. Data is in val.bignum, a pointer and a length. */ +#define QCBOR_TYPE_NEGBIGNUM 10 +/** Type for RFC 3339 date string, possibly with time zone. Data is in val.dateString */ +#define QCBOR_TYPE_DATE_STRING 11 +/** Type for integer seconds since Jan 1970 + floating point fraction. Data is in val.epochDate */ +#define QCBOR_TYPE_DATE_EPOCH 12 +/** A simple type that this CBOR implementation doesn't know about; Type is in val.uSimple. */ +#define QCBOR_TYPE_UKNOWN_SIMPLE 13 +/** Type for the simple value false; nothing more; nothing in val union. */ +#define QCBOR_TYPE_FALSE 20 +/** Type for the simple value true; nothing more; nothing in val union. */ +#define QCBOR_TYPE_TRUE 21 +/** Type for the simple value null; nothing more; nothing in val union. */ +#define QCBOR_TYPE_NULL 22 +/** Type for the simple value undef; nothing more; nothing in val union. */ +#define QCBOR_TYPE_UNDEF 23 +/** Type for a floating point number. Data is in val.float. */ +#define QCBOR_TYPE_FLOAT 26 +/** Type for a double floating point number. Data is in val.double. */ +#define QCBOR_TYPE_DOUBLE 27 +/** For QCBOR_DECODE_MODE_MAP_AS_ARRAY decode mode, a map that is being traversed as an array. See QCBORDecode_Init() */ +#define QCBOR_TYPE_MAP_AS_ARRAY 32 + +#define QCBOR_TYPE_BREAK 31 // Used internally; never returned + +#define QCBOR_TYPE_OPTTAG 254 // Used internally; never returned + + + +/* + Approx Size of this: + 8 + 8 + 1 + 1 + 1 + (1 padding) + (4 padding on 64-bit machine) = 24 for first part (20 on a 32-bit machine) + 16 bytes for the val union + 16 bytes for label union + total = 56 bytes (52 bytes on 32-bit machine) + */ + +/** + QCBORItem holds the type, value and other info for a decoded item returned by GetNextItem(). + */ +typedef struct _QCBORItem { + uint8_t uDataType; /** Tells what element of the val union to use. One of QCBOR_TYPE_XXXX */ + uint8_t uNestingLevel; /** How deep the nesting from arrays and maps are. 0 is the top level with no arrays or maps entered */ + uint8_t uLabelType; /** Tells what element of the label union to use */ + uint8_t uDataAlloc; /** 1 if allocated with string allocator, 0 if not. See QCBORDecode_MakeMallocStringAllocator() */ + uint8_t uLabelAlloc; /** Like uDataAlloc, but for label */ + uint8_t uNextNestLevel; /** If not equal to uNestingLevel, this item closed out at least one map/array */ + + union { + int64_t int64; /** The value for uDataType QCBOR_TYPE_INT64 */ + uint64_t uint64; /** The value for uDataType QCBOR_TYPE_UINT64 */ + + UsefulBufC string; /** The value for uDataType QCBOR_TYPE_BYTE_STRING and QCBOR_TYPE_TEXT_STRING */ + uint16_t uCount; /** The "value" for uDataType QCBOR_TYPE_ARRAY or QCBOR_TYPE_MAP -- the number of items in the array or map + UINT16_MAX when decoding indefinite lengths maps and arrays. */ + double dfnum; /** The value for uDataType QCBOR_TYPE_DOUBLE */ + struct { + int64_t nSeconds; + double fSecondsFraction; + } epochDate; /** The value for uDataType QCBOR_TYPE_DATE_EPOCH */ + UsefulBufC dateString; /** The value for uDataType QCBOR_TYPE_DATE_STRING */ + UsefulBufC bigNum; /** The value for uDataType QCBOR_TYPE_BIGNUM */ + uint8_t uSimple; /** The integer value for unknown simple types */ + uint64_t uTagV; + + } val; /** The union holding the item's value. Select union member based on uDataType */ + + union { + UsefulBufC string; /** The label for uLabelType QCBOR_TYPE_BYTE_STRING and QCBOR_TYPE_TEXT_STRING */ + int64_t int64; /** The label for uLabelType for QCBOR_TYPE_INT64 */ + uint64_t uint64; /** The label for uLabelType for QCBOR_TYPE_UINT64 */ + } label; /** Union holding the different label types selected based on uLabelType */ + + uint64_t uTagBits; /** Bit indicating which tags (major type 6) on this item. */ + +} QCBORItem; + + +/** + This is a set of functions and pointer context (in object-oriented parlance, + an "object") used to allocate memory for coalescing the segments of an indefinite + length string into one. + + The fAllocate function works as an initial allocator and a reallocator to + expand the string for each new segment. When it is an initial allocator + pOldMem is NULL. + + The fFree function is called to clean up an individual allocation when an error occurs. + + The fDesctructor function is called when QCBORDecode_Finish is called. + + Any memory allocated with this will be marked by setting uDataAlloc + or uLabelAlloc in the QCBORItem structure so the caller knows they + have to free it. + + fAllocate is only ever called to increase the single most recent + allocation made, making implementation of a memory pool very simple. + + fFree is also only called on the single most recent allocation. + */ +typedef struct { + void *pAllocaterContext; + UsefulBuf (*fAllocate)(void *pAllocaterContext, void *pOldMem, size_t uNewSize); + void (*fFree)(void *pAllocaterContext, void *pMem); + void (*fDestructor)(void *pAllocaterContext); +} QCBORStringAllocator; + + +/** + This only matters if you use a string allocator + and and set it up with QCBORDecode_SetMemPool(). It is + the size of the overhead needed needed by + QCBORDecode_SetMemPool(). If you write your own + string allocator or use the separately available malloc + based string allocator, this size will not apply + */ +#define QCBOR_DECODE_MIN_MEM_POOL_SIZE 72 + + +/** + This is used to tell the decoder about tags that it should + record in uTagBits in QCBORItem beyond the built-in + tags. puTags points to an + array of uint64_t integers that are the tags. uNumTags + is the number of integers in the array. The maximum + size is QCBOR_MAX_CUSTOM_TAGS. See QCBORDecode_IsTagged() + and QCBORDecode_SetCallerAddedTagMap(). + */ +typedef struct { + uint8_t uNumTags; + const uint64_t *puTags; +} QCBORTagListIn; + + +/** + This is for QCBORDecode_GetNextWithTags() to be able to return the + full list of tags on an item. It not needed for most CBOR protocol + implementations. Its primary use is for pretty-printing CBOR or + protocol conversion to another format. + + On input, puTags points to a buffer to be filled in + and uNumAllocated is the number of uint64_t values + in the buffer. + + On output the buffer contains the tags for the item. + uNumUsed tells how many there are. + */ +typedef struct { + uint8_t uNumUsed; + uint8_t uNumAllocated; + uint64_t *puTags; +} QCBORTagListOut; + + +/** + QCBOREncodeContext is the data type that holds context for all the + encoding functions. It is less than 200 bytes, so it can go on + the stack. The contents are opaque, and the caller should not access + any internal items. A context may be re used serially as long as + it is re initialized. + */ +typedef struct _QCBOREncodeContext QCBOREncodeContext; + + +/** + Initialize the the encoder to prepare to encode some CBOR. + + @param[in,out] pCtx The encoder context to initialize. + @param[in] Storage The buffer into which this encoded result will be placed. + + Call this once at the start of an encoding of a CBOR structure. Then + call the various QCBOREncode_AddXXX() functions to add the data + items. Then call QCBOREncode_Finish(). + + The maximum output buffer is UINT32_MAX (4GB). This is not a practical + limit in any way and reduces the memory needed by the implementation. + The error QCBOR_ERR_BUFFER_TOO_LARGE will be returned by QCBOR_Finish() + if a larger buffer length is passed in. + + If this is called with pBuf as NULL and uBufLen a large value like + UINT32_MAX, all the QCBOREncode_AddXXXX() functions and + QCBORE_Encode_Finish() can still be called. No data will be encoded, + but the length of what would be encoded will be calculated. The + length of the encoded structure will be handed back in the call to + QCBOREncode_Finish(). You can then allocate a buffer of that size + and call all the encoding again, this time to fill in the buffer. + + A QCBORContext can be reused over and over as long as + QCBOREncode_Init() is called. + */ +void QCBOREncode_Init(QCBOREncodeContext *pCtx, UsefulBuf Storage); + + +/** + @brief Add a signed 64-bit integer to the encoded output. + + @param[in] pCtx The encoding context to add the integer to. + @param[in] nNum The integer to add. + + The integer will be encoded and added to the CBOR output. + + This function figures out the size and the sign and encodes in the + correct minimal CBOR. Specifically, it will select CBOR major type 0 or 1 + based on sign and will encode to 1, 2, 4 or 8 bytes depending on the + value of the integer. Values less than 24 effectively encode to one + byte because they are encoded in with the CBOR major type. This is + a neat and efficient characteristic of CBOR that can be taken + advantage of when designing CBOR-based protocols. If integers like + tags can be kept between -23 and 23 they will be encoded in one byte + including the major type. + + If you pass a smaller int, say an int16_t or a small value, say 100, + the encoding will still be CBOR's most compact that can represent the + value. For example, CBOR always encodes the value 0 as one byte, + 0x00. The representation as 0x00 includes identification of the type + as an integer too as the major type for an integer is 0. See RFC 7049 + Appendix A for more examples of CBOR encoding. This compact encoding + is also canonical CBOR as per section 3.9 in RFC 7049. + + There are no functions to add int16_t or int32_t because they are + not necessary because this always encodes to the smallest number + of bytes based on the value (If this code is running on a 32-bit + machine having a way to add 32-bit integers would reduce code size some). + + If the encoding context is in an error state, this will do + nothing. If an error occurs when adding this integer, the internal + error flag will be set, and the error will be returned when + QCBOREncode_Finish() is called. + + See also QCBOREncode_AddUInt64(). + */ +void QCBOREncode_AddInt64(QCBOREncodeContext *pCtx, int64_t nNum); + +static void QCBOREncode_AddInt64ToMap(QCBOREncodeContext *pCtx, const char *szLabel, int64_t uNum); + +static void QCBOREncode_AddInt64ToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, int64_t uNum); + + +/** + @brief Add an unsigned 64-bit integer to the encoded output. + + @param[in] pCtx The encoding context to add the integer to. + @param[in] uNum The integer to add. + + The integer will be encoded and added to the CBOR output. + + The only reason so use this function is for integers larger than + INT64_MAX and smaller than UINT64_MAX. Otherwise QCBOREncode_AddInt64() + will work fine. + + Error handling is the same as for QCBOREncode_AddInt64(). + */ +void QCBOREncode_AddUInt64(QCBOREncodeContext *pCtx, uint64_t uNum); + +static void QCBOREncode_AddUInt64ToMap(QCBOREncodeContext *pCtx, const char *szLabel, uint64_t uNum); + +static void QCBOREncode_AddUInt64ToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, uint64_t uNum); + + +/** + + @brief Add a UTF-8 text string to the encoded output + + @param[in] pCtx The context to initialize. + @param[in] Text Pointer and length of text to add. + + The text passed in must be unencoded UTF-8 according to RFC + 3629. There is no NULL termination. The text is added as CBOR + major type 3. + + If called with nBytesLen equal to 0, an empty string will be + added. When nBytesLen is 0, pBytes may be NULL. + + Note that the restriction of the buffer length to an uint32_t is + entirely intentional as this encoder is not capable of encoding + lengths greater. This limit to 4GB for a text string should not be a + problem. + + Error handling is the same as QCBOREncode_AddInt64(). + */ +static void QCBOREncode_AddText(QCBOREncodeContext *pCtx, UsefulBufC Text); + +static void QCBOREncode_AddTextToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Text); + +static void QCBOREncode_AddTextToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Text); + + +/** + @brief Add a UTF-8 text string to the encoded output + + @param[in] pCtx The context to initialize. + @param[in] szString Null-terminated text to add. + + This works the same as QCBOREncode_AddText(). + */ +static void QCBOREncode_AddSZString(QCBOREncodeContext *pCtx, const char *szString); + +static void QCBOREncode_AddSZStringToMap(QCBOREncodeContext *pCtx, const char *szLabel, const char *szString); + +static void QCBOREncode_AddSZStringToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, const char *szString); + + +/** + @brief Add a floating-point number to the encoded output + + @param[in] pCtx The encoding context to add the float to. + @param[in] dNum The double precision number to add. + + This outputs a floating-point number with CBOR major type 7. + + This will selectively encode the double-precision floating point + number as either double-precision, single-precision or + half-precision. It will always encode infinity, NaN and 0 has half + precision. If no precision will be lost in the conversion to + half-precision then it will be converted and encoded. If not and no + precision will be lost in conversion to single-precision, then it + will be converted and encoded. If not, then no conversion is + performed, and it encoded as a double. + + Half-precision floating point numbers take up 2 bytes, half that of + single-precision, one quarter of double-precision + + This automatically reduces the size of encoded messages a lot, maybe + even by four if most of values are 0, infinity or NaN. + + On decode, these will always be returned as a double. + + Error handling is the same as QCBOREncode_AddInt64(). + */ +void QCBOREncode_AddDouble(QCBOREncodeContext *pCtx, double dNum); + +static void QCBOREncode_AddDoubleToMap(QCBOREncodeContext *pCtx, const char *szLabel, double dNum); + +static void QCBOREncode_AddDoubleToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, double dNum); + + +/** + @brief[in] Add an optional tag + + @param[in] pCtx The encoding context to add the integer to. + @param[in] uTag The tag to add + + This outputs a CBOR major type 6 optional tag. + + The tag is applied to the next data item added to the encoded + output. That data item that is to be tagged can be of any major + CBOR type. Any number of tags can be added to a data item by calling + this multiple times before the data item is added. + + For many of the common standard tags a function to encode + data using it already exists and this is not needed. For example, + QCBOREncode_AddDateEpoch() already exists to output + integers representing dates with the right tag. +*/ +void QCBOREncode_AddTag(QCBOREncodeContext *pCtx,uint64_t uTag); + + +/** + @brief Add an epoch-based date + + @param[in] pCtx The encoding context to add the simple value to. + @param[in] date Number of seconds since 1970-01-01T00:00Z in UTC time. + + As per RFC 7049 this is similar to UNIX/Linux/POSIX dates. This is + the most compact way to specify a date and time in CBOR. Note that this + is always UTC and does not include the time zone. Use + QCBOREncode_AddDateString() if you want to include the time zone. + + The integer encoding rules apply here so the date will be encoded in a + minimal number of 1, 2 4 or 8 bytes. Until about the year 2106 these + dates should encode in 6 bytes -- one byte for the tag, one byte for the type + and 4 bytes for the integer. + + If you care about leap-seconds and that level of accuracy, make sure the + system you are running this code on does it correctly. This code just takes + the value passed in. + + This implementation cannot encode fractional seconds using float or double + even though that is allowed by CBOR, but you can encode them if you + want to by calling QCBOREncode_AddDouble() + with the right parameters. + + Error handling is the same as QCBOREncode_AddInt64(). + */ +static void QCBOREncode_AddDateEpoch(QCBOREncodeContext *pCtx, int64_t date); + +static void QCBOREncode_AddDateEpochToMap(QCBOREncodeContext *pCtx, const char *szLabel, int64_t date); + +static void QCBOREncode_AddDateEpochToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, int64_t date); + + +/** + @brief Add a byte string to the encoded output. + + @param[in] pCtx The context to initialize. + @param[in] Bytes Pointer and length of the input data. + + Simply adds the bytes to the encoded output as CBOR major type 2. + + If called with Bytes.len equal to 0, an empty string will be + added. When Bytes.len is 0, Bytes.ptr may be NULL. + + Error handling is the same as QCBOREncode_AddInt64(). + */ +static void QCBOREncode_AddBytes(QCBOREncodeContext *pCtx, UsefulBufC Bytes); + +static void QCBOREncode_AddBytesToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Bytes); + +static void QCBOREncode_AddBytesToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Bytes); + + + +/** + @brief Add a binary UUID to the encoded output. + + @param[in] pCtx The context to initialize. + @param[in] Bytes Pointer and length of the binary UUID. + + A binary UUID as defined in RFC 4122 is added to the ouput. + + It is output as CBOR major type 2, a binary string, with + optional tag 36 indicating the binary string is a UUID. + */ +static void QCBOREncode_AddBinaryUUID(QCBOREncodeContext *pCtx, UsefulBufC Bytes); + +static void QCBOREncode_AddBinaryUUIDToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Bytes); + +static void QCBOREncode_AddBinaryUUIDToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Bytes); + + +/** + @brief Add a positive big number to the encoded output. + + @param[in] pCtx The context to initialize. + @param[in] Bytes Pointer and length of the big number. + + Big numbers are integers larger than 64-bits. Their format + is described in RFC 7049. + + It is output as CBOR major type 2, a binary string, with + optional tag 2 indicating the binary string is a positive big + number. + + Often big numbers are used to represent cryptographic keys, + however, COSE which defines representations for keys chose not + to use this particular type. + */ +static void QCBOREncode_AddPositiveBignum(QCBOREncodeContext *pCtx, UsefulBufC Bytes); + +static void QCBOREncode_AddPositiveBignumToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Bytes); + +static void QCBOREncode_AddPositiveBignumToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Bytes); + + +/** + @brief Add a negative big number to the encoded output. + + @param[in] pCtx The context to initialize. + @param[in] Bytes Pointer and length of the big number. + + Big numbers are integers larger than 64-bits. Their format + is described in RFC 7049. + + It is output as CBOR major type 2, a binary string, with + optional tag 2 indicating the binary string is a negative big + number. + + Often big numbers are used to represent cryptographic keys, + however, COSE which defines representations for keys chose not + to use this particular type. + */ +static void QCBOREncode_AddNegativeBignum(QCBOREncodeContext *pCtx, UsefulBufC Bytes); + +static void QCBOREncode_AddNegativeBignumToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Bytes); + +static void QCBOREncode_AddNegativeBignumToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Bytes); + + +/** + @brief Add a text URI to the encoded output. + + @param[in] pCtx The context to initialize. + @param[in] URI Pointer and length of the URI. + + The format of URI is RFC 3986. + + It is output as CBOR major type 3, a text string, with + optional tag 32 indicating the text string is a URI. + */ +static void QCBOREncode_AddURI(QCBOREncodeContext *pCtx, UsefulBufC URI); + +static void QCBOREncode_AddURIToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC URI); + +static void QCBOREncode_AddURIToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC URI); + + +/** + @brief Add base 64-encoded text to encoded output. + + @param[in] pCtx The context to initialize. + @param[in] B64Text Pointer and length of the base-64 encoded text. + + The text content is base 64 encoded data per RFC 4648. + + It is output as CBOR major type 3, a text string, with + optional tag 34 indicating the text string is a URI. + */ +static void QCBOREncode_AddB64Text(QCBOREncodeContext *pCtx, UsefulBufC B64Text); + +static void QCBOREncode_AddB64TextToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC B64Text); + +static void QCBOREncode_AddB64TextToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC B64Text); + + +/** + @brief Add base 64URL -encoded URL to encoded output. + + @param[in] pCtx The context to initialize. + @param[in] B64Text Pointer and length of the base-64 encoded text. + + The text content is base 64 URL format encoded text as per RFC 4648. + + It is output as CBOR major type 3, a text string, with + optional tag 33 indicating the text string is a URI. + */ +static void QCBOREncode_AddB64URLText(QCBOREncodeContext *pCtx, UsefulBufC B64Text); + +static void QCBOREncode_AddB64URLTextToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC B64Text); + +static void QCBOREncode_AddB64URLTextToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC B64Text); + + +/** + @brief Add Perl Compatible Regular Expression + + @param[in] pCtx The context to initialize. + @param[in] Regex Pointer and length of the regular expression. + + The text content is Perl Compatible Regular + Expressions (PCRE) / JavaScript syntax [ECMA262]. + + It is output as CBOR major type 3, a text string, with + optional tag 35 indicating the text string is a regular expression. + */ +static void QCBOREncode_AddRegex(QCBOREncodeContext *pCtx, UsefulBufC Regex); + +static void QCBOREncode_AddRegexToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Regex); + +static void QCBOREncode_AddRegexToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Regex); + + +/** + @brief MIME encoded text to the encoded output. + + @param[in] pCtx The context to initialize. + @param[in] MIMEData Pointer and length of the regular expression. + + The text content is in MIME format per RFC 2045 including the headers. + + It is output as CBOR major type 3, a text string, with + optional tag 36 indicating the text string is MIME data. + */ +static void QCBOREncode_AddMIMEData(QCBOREncodeContext *pCtx, UsefulBufC MIMEData); + +static void QCBOREncode_AddMIMEDataToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC MIMEData); + +static void QCBOREncode_AddMIMEDataToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC MIMEData); + + +/** + @brief Add an RFC 3339 date string + + @param[in] pCtx The encoding context to add the simple value to. + @param[in] szDate Null-terminated string with date to add + + The string szDate should be in the form of RFC 3339 as defined by section + 3.3 in RFC 4287. This is as described in section 2.4.1 in RFC 7049. + + Note that this function doesn't validate the format of the date string + at all. If you add an incorrect format date string, the generated + CBOR will be incorrect and the receiver may not be able to handle it. + + Error handling is the same as QCBOREncode_AddInt64(). + */ +static void QCBOREncode_AddDateString(QCBOREncodeContext *pCtx, const char *szDate); + +static void QCBOREncode_AddDateStringToMap(QCBOREncodeContext *pCtx, const char *szLabel, const char *szDate); + +static void QCBOREncode_AddDateStringToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, const char *szDate); + + +/** + @brief Add a standard boolean. + + @param[in] pCtx The encoding context to add the simple value to. + @param[in] b true or false from stdbool. Anything will result in an error. + + Adds a boolean value as CBOR major type 7. + + Error handling is the same as QCBOREncode_AddInt64(). + */ +static void QCBOREncode_AddBool(QCBOREncodeContext *pCtx, bool b); + +static void QCBOREncode_AddBoolToMap(QCBOREncodeContext *pCtx, const char *szLabel, bool b); + +static void QCBOREncode_AddBoolToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, bool b); + + + +/** + @brief Add a NULL to the encoded output. + + @param[in] pCtx The encoding context to add the simple value to. + + Adds the NULL value as CBOR major type 7. + + This NULL doesn't have any special meaning in CBOR such as a terminating + value for a string or an empty value. + + Error handling is the same as QCBOREncode_AddInt64(). + */ +static void QCBOREncode_AddNULL(QCBOREncodeContext *pCtx); + +static void QCBOREncode_AddNULLToMap(QCBOREncodeContext *pCtx, const char *szLabel); + +static void QCBOREncode_AddNULLToMapN(QCBOREncodeContext *pCtx, int64_t nLabel); + + +/** + @brief Add an "undef" to the encoded output. + + @param[in] pCtx The encoding context to add the simple value to. + + Adds the undef value as CBOR major type 7. + + Note that this value will not translate to JSON. + + This Undef doesn't have any special meaning in CBOR such as a terminating + value for a string or an empty value. + + Error handling is the same as QCBOREncode_AddInt64(). + */ +static void QCBOREncode_AddUndef(QCBOREncodeContext *pCtx); + +static void QCBOREncode_AddUndefToMap(QCBOREncodeContext *pCtx, const char *szLabel); + +static void QCBOREncode_AddUndefToMapN(QCBOREncodeContext *pCtx, int64_t nLabel); + + +/** + @brief Indicates that the next items added are in an array. + + @param[in] pCtx The encoding context to open the array in. + + Arrays are the basic CBOR aggregate or structure type. Call this + function to start or open an array. Then call the various AddXXX + functions to add the items that go into the array. Then call + QCBOREncode_CloseArray() when all items have been added. The data + items in the array can be of any type and can be of mixed types. + + Nesting of arrays and maps is allowed and supported just by calling + QCBOREncode_OpenArray() again before calling CloseArray. While CBOR + has no limit on nesting, this implementation does in order to keep it + smaller and simpler. The limit is QCBOR_MAX_ARRAY_NESTING. This is + the max number of times this can be called without calling + QCBOREncode_CloseArray(). QCBOREncode_Finish() will return + QCBOR_ERR_ARRAY_NESTING_TOO_DEEP when it is called as this function + just sets an error state and returns no value when this occurs. + + If you try to add more than QCBOR_MAX_ITEMS_IN_ARRAY items to a + single array or map, QCBOR_ERR_ARRAY_TOO_LONG will be returned when + QCBOREncode_Finish() is called. + + An array itself must have a label if it is being added to a map. + Note that array elements do not have labels (but map elements do). + + An array itself may be tagged. + */ +static void QCBOREncode_OpenArray(QCBOREncodeContext *pCtx); + +static void QCBOREncode_OpenArrayInMap(QCBOREncodeContext *pCtx, const char *szLabel); + +static void QCBOREncode_OpenArrayInMapN(QCBOREncodeContext *pCtx, int64_t nLabel); + + +/** + @brief Close an open array. + + @param[in] pCtx The context to add to. + + The closes an array opened by QCBOREncode_OpenArray(). It reduces + nesting level by one. All arrays (and maps) must be closed before + calling QCBOREncode_Finish(). + + When an error occurs as a result of this call, the encoder records + the error and enters the error state. The error will be returned when + QCBOREncode_Finish() is called. + + If this has been called more times than QCBOREncode_OpenArray(), then + QCBOR_ERR_TOO_MANY_CLOSES will be returned when QCBOREncode_Finish() + is called. + + If this is called and it is not an array that is currently open, + QCBOR_ERR_CLOSE_MISMATCH will be returned when QCBOREncode_Finish() + is called. + */ +static void QCBOREncode_CloseArray(QCBOREncodeContext *pCtx); + + +/** + @brief Indicates that the next items added are in a map. + + @param[in] pCtx The context to add to. + + See QCBOREncode_OpenArray() for more information, particularly error + handling. + + CBOR maps are an aggregate type where each item in the map consists + of a label and a value. They are similar to JSON objects. + + The value can be any CBOR type including another map. + + The label can also be any CBOR type, but in practice they are + typically, integers as this gives the most compact output. They might + also be text strings which gives readability and translation to JSON. + + Every QCBOREncode_AddXXX() call has once version that is "InMap" for + adding items to maps with string labels and on that is "InMapN" that + is for adding with integer labels. + + RFC 7049 uses the term "key" instead of "label". + + If you wish to use map labels that are neither integer labels or + text strings, then just call the QCBOREncode_AddXXX() function + explicitly to add the label. Then call it again to add the value. + + See the RFC7049 for a lot more information on creating maps. + */ +static void QCBOREncode_OpenMap(QCBOREncodeContext *pCtx); + +static void QCBOREncode_OpenMapInMap(QCBOREncodeContext *pCtx, const char *szLabel); + +static void QCBOREncode_OpenMapInMapN(QCBOREncodeContext *pCtx, int64_t nLabel); + + + +/** + @brief Close an open map. + + @param[in] pCtx The context to add to. + + The closes a map opened by QCBOREncode_OpenMap(). It reduces nesting + level by one. + + When an error occurs as a result of this call, the encoder records + the error and enters the error state. The error will be returned when + QCBOREncode_Finish() is called. + + If this has been called more times than QCBOREncode_OpenMap(), + then QCBOR_ERR_TOO_MANY_CLOSES will be returned when + QCBOREncode_Finish() is called. + + If this is called and it is not a map that is currently + open, QCBOR_ERR_CLOSE_MISMATCH will be returned when QCBOREncode_Finish() + is called. + */ +static void QCBOREncode_CloseMap(QCBOREncodeContext *pCtx); + + +/** + @brief Indicate start of encoded CBOR to be wrapped in a bstr. + + @param[in] pCtx The context to add to. + + All added encoded items between this call and a call to + QCBOREncode_CloseBstrWrap() will be wrapped in a bstr. They will + appear in the final output as a byte string. That byte string will + contain encoded CBOR. + + The typical use case is for encoded CBOR that is to be + cryptographically hashed, as part of a COSE (RFC 8152) + implementation. This avoids having to encode the items first in one + buffer (e.g., the COSE payload) and then add that buffer as a bstr to + another encoding (e.g. the COSE to-be-signed bytes, the + Sig_structure) potentially saving a lot of memory. + + When constructing cryptographically signed CBOR objects, maps or + arrays, they typically are encoded normally and then wrapped as a + byte string. The COSE standard for example does this. The wrapping is + simply treating the encoded CBOR map as a byte string. + + The stated purpose of this wrapping is to prevent code relaying the + signed data but not verifying it from tampering with the signed data + thus making the signature unverifiable. It is also quite beneficial + for the signature verification code. Standard CBOR parsers usually do + not give access to partially parsed CBOR as would be need to check + the signature of some CBOR. With this wrapping, standard CBOR parsers + can be used to get to all the data needed for a signature + verification. + */ +static void QCBOREncode_BstrWrap(QCBOREncodeContext *pCtx); + +static void QCBOREncode_BstrWrapInMap(QCBOREncodeContext *pCtx, const char *szLabel); + +static void QCBOREncode_BstrWrapInMapN(QCBOREncodeContext *pCtx, int64_t nLabel); + + +/** + @brief Close a wrapping bstr. + + @param[in] pCtx The context to add to. + @param[out] pWrappedCBOR UsefulBufC containing wrapped bytes + + The closes a wrapping bstr opened by QCBOREncode_BstrWrap(). It reduces + nesting level by one. + + A pointer and length of the enclosed encoded CBOR is returned in + *pWrappedCBOR if it is not NULL. The main purpose of this is so this + data can be hashed (e.g., with SHA-256) as part of a COSE (RFC 8152) + implementation. **WARNING**, this pointer and length should be used + right away before any other calls to QCBOREncode_xxxx() as they will + move data around and the pointer and length will no longer be to the + correct encoded CBOR. + + When an error occurs as a result of this call, the encoder records + the error and enters the error state. The error will be returned when + QCBOREncode_Finish() is called. + + If this has been called more times then QCBOREncode_BstrWrap(), + then QCBOR_ERR_TOO_MANY_CLOSES will be returned when + QCBOREncode_Finish() is called. + + If this is called and it is not a wrapping bstr that is currently + open, QCBOR_ERR_CLOSE_MISMATCH will be returned when QCBOREncode_Finish() + is called. + */ +static void QCBOREncode_CloseBstrWrap(QCBOREncodeContext *pCtx, UsefulBufC *pWrappedCBOR); + + +/** + @brief Add some already-encoded CBOR bytes. + + @param[in] pCtx The context to add to. + @param[in] Encoded The already-encoded CBOR to add to the context. + + The encoded CBOR being added must be fully conforming CBOR. It must + be complete with no arrays or maps that are incomplete. While this + encoder doesn't ever produce indefinite lengths, it is OK for the + raw CBOR added here to have indefinite lengths. + + The raw CBOR added here is not checked in anyway. If it is not + conforming or has open arrays or such, the final encoded CBOR + will probably be wrong or not what was intended. + + If the encoded CBOR being added here contains multiple items, they + must be enclosed in a map or array. At the top level the raw + CBOR must be a single data item. + */ +static void QCBOREncode_AddEncoded(QCBOREncodeContext *pCtx, UsefulBufC Encoded); + +static void QCBOREncode_AddEncodedToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Encoded); + +static void QCBOREncode_AddEncodedToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Encoded); + + +/** + @brief Get the encoded result. + + @param[in] pCtx The context to finish encoding with. + @param[out] pEncodedCBOR Pointer and length of encoded CBOR. + + @return + One of the CBOR error codes. + + If this returns success QCBOR_SUCCESS the encoding was a success and + the return length is correct and complete. + + If no buffer was passed to QCBOR_Init(), then only the length and + number of items was computed. The length is in + pEncodedCBOR->Bytes.len. pEncodedCBOR->Bytes.ptr is NULL. + + If a buffer was passed, then pEncodedCBOR->Bytes.ptr is the same as + the buffer passed to QCBOR_Init() and contains the encoded CBOR + and the length is filled in. + + If an error is returned, the buffer may have partially encoded + incorrect CBOR in it and it should not be used. Likewise, the length + may be incorrect and should not be used. + + Note that the error could have occurred in one of the many + QCBOR_AddXXX calls long before QCBOREncode_Finish() was called. This + error handling approach reduces the CBOR implementation size, but makes + debugging a problem a little more difficult. + */ +QCBORError QCBOREncode_Finish(QCBOREncodeContext *pCtx, UsefulBufC *pEncodedCBOR); + + +/** + @brief Get the encoded CBOR and error status. + + @param[in] pCtx The context to finish encoding with. + @param[out] uEncodedLen The length of the encoded or potentially encoded CBOR in bytes. + + @return + One of the CBOR error codes. + + If this returns success QCBOR_SUCCESS the encoding was a success and + the return length is correct and complete. + + If no buffer was passed to QCBOR_Init(), then only the length was + computed. If a buffer was passed, then the encoded CBOR is in the + buffer. + + If an error is returned, the buffer may have partially encoded + incorrect CBOR in it and it should not be used. Likewise, the length + may be incorrect and should not be used. + + Note that the error could have occurred in one of the many + QCBOR_AddXXX calls long before QCBOREncode_Finish() was called. This + error handling reduces the CBOR implementation size, but makes + debugging harder. + */ +QCBORError QCBOREncode_FinishGetSize(QCBOREncodeContext *pCtx, size_t *uEncodedLen); + + + + + + +/** + QCBORDecodeContext is the data type that holds context decoding the + data items for some received CBOR. It is about 100 bytes, so it can go + on the stack. The contents are opaque, and the caller should not + access any internal items. A context may be re used serially as long + as it is re initialized. + */ +typedef struct _QCBORDecodeContext QCBORDecodeContext; + + +/** + Initialize the CBOR decoder context. + + @param[in] pCtx The context to initialize. + @param[in] EncodedCBOR The buffer with CBOR encoded bytes to be decoded. + @param[in] nMode One of QCBOR_DECODE_MODE_xxx + + Initialize context for a pre-order travesal of the encoded CBOR tree. + + Most CBOR decoding can be completed by calling this function to start + and QCBORDecode_GetNext() in a loop. + + If indefinite length strings are to be decoded, then + QCBORDecode_SetMemPool() or QCBORDecode_SetUpAllocator() must be + called to set up a string allocator. + + If tags other than built-in tags are to be recognized, then + QCBORDecode_SetCallerAddedTagMap() must be called. The built-in tags + are those for which a macro of the form CBOR_TAG_XXX is defined. + + Three decoding modes are supported. In normal mode, + QCBOR_DECODE_MODE_NORMAL, maps are decoded and strings and ints are + accepted as map labels. If a label is other than these, the error + QCBOR_ERR_MAP_LABEL_TYPE is returned by QCBORDecode_GetNext(). + + In strings-only mode, QCBOR_DECODE_MODE_MAP_STRINGS_ONLY, only text + strings are accepted for map labels. This lines up with CBOR that + converts to JSON. The error QCBOR_ERR_MAP_LABEL_TYPE is returned by + QCBORDecode_GetNext() if anything but a text string label is + encountered. + + In QCBOR_DECODE_MODE_MAP_AS_ARRAY maps are treated as special arrays. + They will be return with special uDataType QCBOR_TYPE_MAP_AS_ARRAY + and uCount, the number of items, will be double what it would be + for a normal map because the labels are also counted. This mode + is useful for decoding CBOR that has labels that are not + integers or text strings, but the caller must manage much of + the map decoding. + */ +void QCBORDecode_Init(QCBORDecodeContext *pCtx, UsefulBufC EncodedCBOR, QCBORDecodeMode nMode); + + +/** + @brief Set up the MemPool string allocator for indefinite length strings. + + @param[in] pCtx The decode context. + @param[in] MemPool The pointer and length of the memory pool. + @param[in] bAllStrings true means to put even definite length strings in the pool. + + @return error if the MemPool was less than QCBOR_DECODE_MIN_MEM_POOL_SIZE. + + Indefinite length strings (text and byte) cannot be decoded unless + there is a string allocator configured. MemPool is a simple built-in + string allocator that allocates bytes from a memory pool handed to it + by calling this function. The memory pool is just a pointer and + length for some block of memory that is to be used for string + allocation. It can come from the stack, heap or other. + + The memory pool must be QCBOR_DECODE_MIN_MEM_POOL_SIZE plus space for + all the strings allocated. There is no overhead per string allocated + + This memory pool is used for all indefinite length strings that are + text strings or byte strings, including strings used as labels. + + The pointers to strings in QCBORItem will point into the memory pool set + here. They do not need to be individually freed. Just discard the buffer + when they are no longer needed. + + If bAllStrings is set, then the size will be the overhead plus the + space to hold **all** strings, definite and indefinite length, value + or label. The advantage of this is that after the decode is complete, + the original memory holding the encoded CBOR does not need to remain + valid. + + If this function is never called because there is no need to support + indefinite length strings, the MemPool implementation should be + dead-stripped by the loader and not add to code size. + */ +QCBORError QCBORDecode_SetMemPool(QCBORDecodeContext *pCtx, UsefulBuf MemPool, bool bAllStrings); + + +/** + @brief Sets up a custom string allocator for indefinite length strings + + @param[in] pCtx The decoder context to set up an allocator for + @param[in] pAllocator The string allocator "object" + + See QCBORStringAllocator for the requirements of the string allocator. + + Typically, this is used if the simple MemPool allocator isn't desired. + + A malloc based string allocator can be obtained by calling + QCBOR_DMalloc(). This function is supply separately from qcbor + to keep qcbor smaller and neater. It is in a separate + GitHub repository. + + You can also write your own allocator. Create the allocate, free, + and destroy functions and put pointers to them in a QCBORStringAllocator. + */ +void QCBORDecode_SetUpAllocator(QCBORDecodeContext *pCtx, const QCBORStringAllocator *pAllocator, bool bAllStrings); + + +/** + @brief Configure list of caller selected tags to be recognized + + @param[in] pCtx The decode context. + @param[out] pTagList Structure holding the list of tags to configure + + This is used to tell the decoder about tags beyond those that are + built-in that should be recognized. The built-in tags are those + with macros of the form CBOR_TAG_XXX. + + See description of QCBORTagListIn. + */ +void QCBORDecode_SetCallerConfiguredTagList(QCBORDecodeContext *pCtx, const QCBORTagListIn *pTagList); + + +/** + @brief Gets the next item (integer, byte string, array...) in pre order traversal of CBOR tree + + @param[in] pCtx The decoder context. + @param[out] pDecodedItem Holds the CBOR item just decoded. + + @return 0 or error. All errors except QCBOR_ERR_TOO_MANY_TAGS + and QCBOR_ERR_STRING_ALLOCATE indicate that the CBOR input + could not be decoded. In most cases + this is because the CBOR is invalid. In a few cases + (QCBOR_ERR_ARRAY_NESTING_TOO_DEEP, QCBOR_ERR_INT_OVERFLOW, + QCBOR_ERR_DATE_OVERFLOW) it is because the CBOR is beyond + the limits of what this implementation can handle. + QCBOR_ERR_NO_STRING_ALLOCATOR indicates CBOR that cannot + be handled unless a string allocator is configured. + QCBOR_ERR_MAP_LABEL_TYPE is in a way a limitation of + this implementation, but can be avoided by decoding + in QCBOR_DECODE_MODE_MAP_AS_ARRAY mode. + + pDecodedItem is filled in with the value parsed. Generally, the + following data is returned in the structure. + + - The data type in uDataType which indicates which member of the val + union the data is in. This decoder figures out the type based on the + CBOR major type, the CBOR "additionalInfo", the CBOR optional tags + and the value of the integer. + + - The value of the item, which might be an integer, a pointer and a + length, the count of items in an array, a floating-point number or + other. + + - The nesting level for maps and arrays. + + - The label for an item in a map, which may be a text or byte string or an integer. + + - The CBOR optional tag or tags. + + See documentation on in the data type QCBORItem for all the details + on what is returned. + + This function also handles arrays and maps. When first encountered a + QCBORItem will be returned with major type CBOR_MAJOR_TYPE_ARRAY or + CBOR_MAJOR_TYPE_ARRAY_MAP. QCBORItem.val.uCount will indicate the number + of Items in the array or map. Typically, an implementation will call + QCBORDecode_GetNext() in a for loop to fetch them all. When decoding + indefinite length maps and arrays, QCBORItem.val.uCount is UINT16_MAX + and uNextNestLevel must be used to know when the end of a map + or array is reached. + + Nesting level 0 is the outside top-most nesting level. For example, in + a CBOR structure with two items, an integer and a byte string only, + both would be at nesting level 0. A CBOR structure with an array + open, an integer and a byte string, would have the integer and byte + string as nesting level 1. + + Here is an example of how the nesting level is reported with no arrays + or maps at all + + @verbatim + CBOR Structure Nesting Level + Integer 0 + Byte String 0 + @endverbatim + + Here is an example of how the nesting level is reported with an a simple + array and some top-level items. + + @verbatim + Integer 0 + Array (with 2 items) 0 + Byte String 1 + Byte string 1 + Integer 0 + @endverbatim + + + Here's a more complex example + @verbatim + + Map with 2 items 0 + Text string 1 + Array with 3 integers 1 + integer 2 + integer 2 + integer 2 + text string 1 + byte string 1 + @endverbatim + + In QCBORItem, uNextNestLevel is the nesting level for the next call + to QCBORDecode_GetNext(). It indicates if any maps or arrays were closed + out during the processing of the just-fecthed QCBORItem. This processing + includes a look-ahead for any breaks that close out indefinite length + arrays or maps. This value is needed to be able to understand the + hierarchical structure. If uNextNestLevel is not equal to uNestLevel + the end of the current map or array has been encountered. This + works the same for both definite and indefinite length arrays. + + Most uses of this decoder will not need to do anything extra for + tag handling. The built-in tags, those with a macro of the form + CBOR_TAG_XXXX, will be enough. + + If tags beyond built-in tags are to be recognized, they must be + configured by calling QCBORDecode_SetCallerConfiguredTags(). If + a tag is not recognized it is silently ignored. + + Several tagged types are automatically recognized and decoded and + returned in their decoded form. + + To find out if a QCBORItem was tagged with a particular tag + call QCBORDecode_IsTagged(). This works only for built-in + tags and caller-configured tags. + + To get the full list of tags on an Item without having to + pre-configure any predetermined list of tags use + QCBORDecode_GetNextWithTags(). + */ +QCBORError QCBORDecode_GetNext(QCBORDecodeContext *pCtx, QCBORItem *pDecodedItem); + + +/** + @brief Gets the next item including full list of tags for item + + @param[in] pCtx The decoder context. + @param[out] pDecodedItem Holds the CBOR item just decoded. + @param[in,out] pTagList On input array to put tags in; on output the tags on this item. + + @return 0 or error. + + This works the same as QCBORDecode_GetNext() except that it also returns + the full list of tags for the data item. This function should only + be needed when parsing CBOR to print it out or convert it to some other + format. It should not be needed in an actual CBOR protocol implementation. + + Tags will be returned here whether or not they are in the built-in or + caller-configured tag lists. + + CBOR has no upper bound of limit on the number of tags that can be + associated with a data item. In practice the number of tags on an item + will usually be small, perhaps less than five. This will return an error + if the array in pTagList is too small to hold all the tags for an item. + + (This function is separate from QCBORDecode_GetNext() so as to not have to + make QCBORItem large enough to be able to hold a full list of tags. Even a list of + five tags would nearly double its size because tags can be a uint64_t). + */ +QCBORError QCBORDecode_GetNextWithTags(QCBORDecodeContext *pCtx, QCBORItem *pDecodedItem, QCBORTagListOut *pTagList); + + +/** + @brief Determine if a CBOR item was tagged with a particular tag + + @param[in] pCtx The decoder context. + @param[in] pItem The CBOR item to check + @param[in] uTag The tag to check + + @return 1 if it was tagged, 0 if not + + QCBORDecode_GetNext() processes tags by looking them up + in two lists and setting a bit corresponding to the tag + in uTagBits in the QCBORItem. To find out if a + QCBORItem was tagged with a particular tag, call + this function. It handles the mapping between + the two lists of tags and the bits set for it. + + The first tag list is the built-in tags, those + with a macro of the form CBOR_TAG_XXX in this + header file. There are up to 48 of these, + corresponding to the lower 48 tag bits. + + The other optional tag list is the ones + the caller configured using QCBORDecode_SetCallerConfiguredTagList() + There are QCBOR_MAX_CUSTOM_TAGS (16) of these corresponding to the + upper 16 tag bits. + + See also QCBORDecode_GetTags() and QCBORDecode_GetNextWithTags(). + */ +int QCBORDecode_IsTagged(QCBORDecodeContext *pCtx, const QCBORItem *pItem, uint64_t uTag); + + +/** + Check whether all the bytes have been decoded and maps and arrays closed. + + @param[in] pCtx The context to check + + @return QCBOR_SUCCESS or error + + This tells you if all the bytes given to QCBORDecode_Init() have + been consumed and whether all maps and arrays were closed. + The decode is considered to be incorrect or incomplete if not + and an error will be returned. + */ +QCBORError QCBORDecode_Finish(QCBORDecodeContext *pCtx); + + + + +/** + Convert int64_t to smaller int's safely + + @param [in] src An int64_t + @param [out] dest A smaller sized int to convert to + + @return 0 on success -1 if not + + When decoding an integer, the CBOR decoder will return the value as an + int64_t unless the integer is in the range of INT64_MAX and + UINT64_MAX. That is, unless the value is so large that it can only be + represented as a uint64_t, it will be an int64_t. + + CBOR itself doesn't size the individual integers it carries at + all. The only limits it puts on the major integer types is that they + are 8 bytes or less in length. Then encoders like this one use the + smallest number of 1, 2, 4 or 8 bytes to represent the integer based + on its value. There is thus no notion that one data item in CBOR is + an 1 byte integer and another is a 4 byte integer. + + The interface to this CBOR encoder only uses 64-bit integers. Some + CBOR protocols or implementations of CBOR protocols may not want to + work with something smaller than a 64-bit integer. Perhaps an array + of 1000 integers needs to be sent and none has a value larger than + 50,000 and are represented as uint16_t. + + The sending / encoding side is easy. Integers are temporarily widened + to 64-bits as a parameter passing through QCBOREncode_AddInt64() and + encoded in the smallest way possible for their value, possibly in + less than an uint16_t. + + On the decoding side the integers will be returned at int64_t even if + they are small and were represented by only 1 or 2 bytes in the + encoded CBOR. The functions here will convert integers to a small + representation with an overflow check. + + (The decoder could have support 8 different integer types and + represented the integer with the smallest type automatically, but + this would have made the decoder more complex and code calling the + decoder more complex in most use cases. In most use cases on 64-bit + machines it is no burden to carry around even small integers as + 64-bit values). + */ +static inline int QCBOR_Int64ToInt32(int64_t src, int32_t *dest) +{ + if(src > INT32_MAX || src < INT32_MIN) { + return -1; + } else { + *dest = (int32_t) src; + } + return 0; +} + +static inline int QCBOR_Int64ToInt16(int64_t src, int16_t *dest) +{ + if(src > INT16_MAX || src < INT16_MIN) { + return -1; + } else { + *dest = (int16_t) src; + } + return 0; +} + +static inline int QCBOR_Int64ToInt8(int64_t src, int8_t *dest) +{ + if(src > INT8_MAX || src < INT8_MIN) { + return -1; + } else { + *dest = (int8_t) src; + } + return 0; +} + +static inline int QCBOR_Int64ToUInt32(int64_t src, uint32_t *dest) +{ + if(src > UINT32_MAX || src < 0) { + return -1; + } else { + *dest = (uint32_t) src; + } + return 0; +} + +static inline int QCBOR_Int64UToInt16(int64_t src, uint16_t *dest) +{ + if(src > UINT16_MAX || src < 0) { + return -1; + } else { + *dest = (uint16_t) src; + } + return 0; +} + +static inline int QCBOR_Int64ToUInt8(int64_t src, uint8_t *dest) +{ + if(src > UINT8_MAX || src < 0) { + return -1; + } else { + *dest = (uint8_t) src; + } + return 0; +} + +static inline int QCBOR_Int64ToUInt64(int64_t src, uint64_t *dest) +{ + if(src > 0) { + return -1; + } else { + *dest = (uint64_t) src; + } + return 0; +} + + + + + +/* =========================================================================== + BEGINNING OF PRIVATE INLINE IMPLEMENTATION + + =========================================================================== */ + +/** + @brief Semi-private method to add a buffer full of bytes to encoded output + + @param[in] pCtx The encoding context to add the integer to. + @param[in] uMajorType The CBOR major type of the bytes. + @param[in] Bytes The bytes to add. + + Use QCBOREncode_AddText() or QCBOREncode_AddBytes() or + QCBOREncode_AddEncoded() instead. They are inline functions + that call this and supply the correct major type. This function + is public to make the inline functions work to keep the overall + code size down and because the C language has no way to make + it private. + + If this is called the major type should be CBOR_MAJOR_TYPE_TEXT_STRING, + CBOR_MAJOR_TYPE_BYTE_STRING or CBOR_MAJOR_NONE_TYPE_RAW. The last + one is special for adding already-encoded CBOR. + */ +void QCBOREncode_AddBuffer(QCBOREncodeContext *pCtx, uint8_t uMajorType, UsefulBufC Bytes); + + +/** + @brief Semi-private method to open a map, array or bstr wrapped CBOR + + @param[in] pCtx The context to add to. + @param[in] uMajorType The major CBOR type to close + + Call QCBOREncode_OpenArray(), QCBOREncode_OpenMap() or + QCBOREncode_BstrWrap() instead of this. + */ +void QCBOREncode_OpenMapOrArray(QCBOREncodeContext *pCtx, uint8_t uMajorType); + + +/** + @brief Semi-private method to close a map, array or bstr wrapped CBOR + + @param[in] pCtx The context to add to. + @param[in] uMajorType The major CBOR type to close + @param[out] pWrappedCBOR UsefulBufC containing wrapped bytes + + Call QCBOREncode_CloseArray(), QCBOREncode_CloseMap() or + QCBOREncode_CloseBstrWrap() instead of this. + */ +void QCBOREncode_CloseMapOrArray(QCBOREncodeContext *pCtx, uint8_t uMajorType, UsefulBufC *pWrappedCBOR); + + +/** + @brief Semi-private method to add simple types. + + @param[in] pCtx The encoding context to add the simple value to. + @param[in] uSize Minimum encoding size for uNum. Usually 0. + @param[in] uNum One of CBOR_SIMPLEV_FALSE through _UNDEF or other. + + This is used to add simple types like true and false. + + Call QCBOREncode_AddBool(), QCBOREncode_AddNULL(), QCBOREncode_AddUndef() + instead of this. + + This function can add simple values that are not defined by CBOR yet. This expansion + point in CBOR should not be used unless they are standardized. + + Error handling is the same as QCBOREncode_AddInt64(). + */ +void QCBOREncode_AddType7(QCBOREncodeContext *pCtx, size_t uSize, uint64_t uNum); + + +static inline void QCBOREncode_AddInt64ToMap(QCBOREncodeContext *pCtx, const char *szLabel, int64_t uNum) +{ + QCBOREncode_AddBuffer(pCtx, CBOR_MAJOR_TYPE_TEXT_STRING, UsefulBuf_FromSZ(szLabel)); // AddSZString not defined yet + QCBOREncode_AddInt64(pCtx, uNum); +} + +static inline void QCBOREncode_AddInt64ToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, int64_t uNum) +{ + QCBOREncode_AddInt64(pCtx, nLabel); + QCBOREncode_AddInt64(pCtx, uNum); +} + + +static inline void QCBOREncode_AddUInt64ToMap(QCBOREncodeContext *pCtx, const char *szLabel, uint64_t uNum) +{ + QCBOREncode_AddBuffer(pCtx, CBOR_MAJOR_TYPE_TEXT_STRING, UsefulBuf_FromSZ(szLabel)); // AddSZString not defined yet + QCBOREncode_AddUInt64(pCtx, uNum); +} + +static inline void QCBOREncode_AddUInt64ToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, uint64_t uNum) +{ + QCBOREncode_AddInt64(pCtx, nLabel); + QCBOREncode_AddUInt64(pCtx, uNum); +} + + +static inline void QCBOREncode_AddText(QCBOREncodeContext *pCtx, UsefulBufC Text) +{ + QCBOREncode_AddBuffer(pCtx, CBOR_MAJOR_TYPE_TEXT_STRING, Text); +} + +static inline void QCBOREncode_AddTextToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Text) +{ + QCBOREncode_AddText(pCtx, UsefulBuf_FromSZ(szLabel)); // AddSZString not defined yet + QCBOREncode_AddText(pCtx, Text); +} + +static inline void QCBOREncode_AddTextToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Text) +{ + QCBOREncode_AddInt64(pCtx, nLabel); + QCBOREncode_AddText(pCtx, Text); +} + + +inline static void QCBOREncode_AddSZString(QCBOREncodeContext *pCtx, const char *szString) +{ + QCBOREncode_AddText(pCtx, UsefulBuf_FromSZ(szString)); +} + +static inline void QCBOREncode_AddSZStringToMap(QCBOREncodeContext *pCtx, const char *szLabel, const char *szString) +{ + QCBOREncode_AddSZString(pCtx, szLabel); + QCBOREncode_AddSZString(pCtx, szString); +} + +static inline void QCBOREncode_AddSZStringToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, const char *szString) +{ + QCBOREncode_AddInt64(pCtx, nLabel); + QCBOREncode_AddSZString(pCtx, szString); +} + + +static inline void QCBOREncode_AddDoubleToMap(QCBOREncodeContext *pCtx, const char *szLabel, double dNum) +{ + QCBOREncode_AddSZString(pCtx, szLabel); + QCBOREncode_AddDouble(pCtx, dNum); +} + +static inline void QCBOREncode_AddDoubleToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, double dNum) +{ + QCBOREncode_AddInt64(pCtx, nLabel); + QCBOREncode_AddDouble(pCtx, dNum); +} + + +static inline void QCBOREncode_AddDateEpoch(QCBOREncodeContext *pCtx, int64_t date) +{ + QCBOREncode_AddTag(pCtx, CBOR_TAG_DATE_EPOCH); + QCBOREncode_AddInt64(pCtx, date); +} + +static inline void QCBOREncode_AddDateEpochToMap(QCBOREncodeContext *pCtx, const char *szLabel, int64_t date) +{ + QCBOREncode_AddSZString(pCtx, szLabel); + QCBOREncode_AddTag(pCtx, CBOR_TAG_DATE_EPOCH); + QCBOREncode_AddInt64(pCtx, date); +} + +static inline void QCBOREncode_AddDateEpochToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, int64_t date) +{ + QCBOREncode_AddInt64(pCtx, nLabel); + QCBOREncode_AddTag(pCtx, CBOR_TAG_DATE_EPOCH); + QCBOREncode_AddInt64(pCtx, date); +} + + +static inline void QCBOREncode_AddBytes(QCBOREncodeContext *pCtx, UsefulBufC Bytes) +{ + QCBOREncode_AddBuffer(pCtx, CBOR_MAJOR_TYPE_BYTE_STRING, Bytes); +} + +static inline void QCBOREncode_AddBytesToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Bytes) +{ + QCBOREncode_AddSZString(pCtx, szLabel); + QCBOREncode_AddBytes(pCtx, Bytes); +} + +static inline void QCBOREncode_AddBytesToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Bytes) +{ + QCBOREncode_AddInt64(pCtx, nLabel); + QCBOREncode_AddBytes(pCtx, Bytes); +} + + +static inline void QCBOREncode_AddBinaryUUID(QCBOREncodeContext *pCtx, UsefulBufC Bytes) +{ + QCBOREncode_AddTag(pCtx, CBOR_TAG_BIN_UUID); + QCBOREncode_AddBytes(pCtx, Bytes); +} + +static inline void QCBOREncode_AddBinaryUUIDToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Bytes) +{ + QCBOREncode_AddSZString(pCtx, szLabel); + QCBOREncode_AddTag(pCtx, CBOR_TAG_BIN_UUID); + QCBOREncode_AddBytes(pCtx, Bytes); +} + +static inline void QCBOREncode_AddBinaryUUIDToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Bytes) +{ + QCBOREncode_AddInt64(pCtx, nLabel); + QCBOREncode_AddTag(pCtx, CBOR_TAG_BIN_UUID); + QCBOREncode_AddBytes(pCtx, Bytes); +} + + +static inline void QCBOREncode_AddPositiveBignum(QCBOREncodeContext *pCtx, UsefulBufC Bytes) +{ + QCBOREncode_AddTag(pCtx, CBOR_TAG_POS_BIGNUM); + QCBOREncode_AddBytes(pCtx, Bytes); +} + +static inline void QCBOREncode_AddPositiveBignumToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Bytes) +{ + QCBOREncode_AddSZString(pCtx, szLabel); + QCBOREncode_AddTag(pCtx, CBOR_TAG_POS_BIGNUM); + QCBOREncode_AddBytes(pCtx, Bytes); +} + +static inline void QCBOREncode_AddPositiveBignumToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Bytes) +{ + QCBOREncode_AddInt64(pCtx, nLabel); + QCBOREncode_AddTag(pCtx, CBOR_TAG_POS_BIGNUM); + QCBOREncode_AddBytes(pCtx, Bytes); +} + + +static inline void QCBOREncode_AddNegativeBignum(QCBOREncodeContext *pCtx, UsefulBufC Bytes) +{ + QCBOREncode_AddTag(pCtx, CBOR_TAG_NEG_BIGNUM); + QCBOREncode_AddBytes(pCtx, Bytes); +} + +static inline void QCBOREncode_AddNegativeBignumToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Bytes) +{ + QCBOREncode_AddSZString(pCtx, szLabel); + QCBOREncode_AddTag(pCtx, CBOR_TAG_NEG_BIGNUM); + QCBOREncode_AddBytes(pCtx, Bytes); +} + +static inline void QCBOREncode_AddNegativeBignumToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Bytes) +{ + QCBOREncode_AddInt64(pCtx, nLabel); + QCBOREncode_AddTag(pCtx, CBOR_TAG_NEG_BIGNUM); + QCBOREncode_AddBytes(pCtx, Bytes); +} + + +static inline void QCBOREncode_AddURI(QCBOREncodeContext *pCtx, UsefulBufC URI) +{ + QCBOREncode_AddTag(pCtx, CBOR_TAG_URI); + QCBOREncode_AddText(pCtx, URI); +} + +static inline void QCBOREncode_AddURIToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC URI) +{ + QCBOREncode_AddSZString(pCtx, szLabel); + QCBOREncode_AddTag(pCtx, CBOR_TAG_URI); + QCBOREncode_AddText(pCtx, URI); +} + +static inline void QCBOREncode_AddURIToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC URI) +{ + QCBOREncode_AddInt64(pCtx, nLabel); + QCBOREncode_AddTag(pCtx, CBOR_TAG_URI); + QCBOREncode_AddText(pCtx, URI); +} + + + +static inline void QCBOREncode_AddB64Text(QCBOREncodeContext *pCtx, UsefulBufC B64Text) +{ + QCBOREncode_AddTag(pCtx, CBOR_TAG_B64); + QCBOREncode_AddText(pCtx, B64Text); +} + +static inline void QCBOREncode_AddB64TextToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC B64Text) +{ + QCBOREncode_AddSZString(pCtx, szLabel); + QCBOREncode_AddTag(pCtx, CBOR_TAG_B64); + QCBOREncode_AddText(pCtx, B64Text); +} + +static inline void QCBOREncode_AddB64TextToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC B64Text) +{ + QCBOREncode_AddInt64(pCtx, nLabel); + QCBOREncode_AddTag(pCtx, CBOR_TAG_B64); + QCBOREncode_AddText(pCtx, B64Text); +} + + +static inline void QCBOREncode_AddB64URLText(QCBOREncodeContext *pCtx, UsefulBufC B64Text) +{ + QCBOREncode_AddTag(pCtx, CBOR_TAG_B64URL); + QCBOREncode_AddText(pCtx, B64Text); +} + +static inline void QCBOREncode_AddB64URLTextToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC B64Text) +{ + QCBOREncode_AddSZString(pCtx, szLabel); + QCBOREncode_AddTag(pCtx, CBOR_TAG_B64URL); + QCBOREncode_AddText(pCtx, B64Text); +} + +static inline void QCBOREncode_AddB64URLTextToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC B64Text) +{ + QCBOREncode_AddInt64(pCtx, nLabel); + QCBOREncode_AddTag(pCtx, CBOR_TAG_B64URL); + QCBOREncode_AddText(pCtx, B64Text); +} + + +static inline void QCBOREncode_AddRegex(QCBOREncodeContext *pCtx, UsefulBufC Bytes) +{ + QCBOREncode_AddTag(pCtx, CBOR_TAG_REGEX); + QCBOREncode_AddText(pCtx, Bytes); +} + +static inline void QCBOREncode_AddRegexToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Bytes) +{ + QCBOREncode_AddSZString(pCtx, szLabel); + QCBOREncode_AddTag(pCtx, CBOR_TAG_REGEX); + QCBOREncode_AddText(pCtx, Bytes); +} + +static inline void QCBOREncode_AddRegexToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Bytes) +{ + QCBOREncode_AddInt64(pCtx, nLabel); + QCBOREncode_AddTag(pCtx, CBOR_TAG_REGEX); + QCBOREncode_AddText(pCtx, Bytes); +} + + +static inline void QCBOREncode_AddMIMEData(QCBOREncodeContext *pCtx, UsefulBufC MIMEData) +{ + QCBOREncode_AddTag(pCtx, CBOR_TAG_MIME); + QCBOREncode_AddText(pCtx, MIMEData); +} + +static inline void QCBOREncode_AddMIMEDataToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC MIMEData) +{ + QCBOREncode_AddSZString(pCtx, szLabel); + QCBOREncode_AddTag(pCtx, CBOR_TAG_MIME); + QCBOREncode_AddText(pCtx, MIMEData); +} + +static inline void QCBOREncode_AddMIMEDataToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC MIMEData) +{ + QCBOREncode_AddInt64(pCtx, nLabel); + QCBOREncode_AddTag(pCtx, CBOR_TAG_MIME); + QCBOREncode_AddText(pCtx, MIMEData); +} + + +static inline void QCBOREncode_AddDateString(QCBOREncodeContext *pCtx, const char *szDate) +{ + QCBOREncode_AddTag(pCtx, CBOR_TAG_DATE_STRING); + QCBOREncode_AddSZString(pCtx, szDate); +} + +static inline void QCBOREncode_AddDateStringToMap(QCBOREncodeContext *pCtx, const char *szLabel, const char *szDate) +{ + QCBOREncode_AddSZString(pCtx, szLabel); + QCBOREncode_AddTag(pCtx, CBOR_TAG_DATE_STRING); + QCBOREncode_AddSZString(pCtx, szDate); +} + +static inline void QCBOREncode_AddDateStringToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, const char *szDate) +{ + QCBOREncode_AddInt64(pCtx, nLabel); + QCBOREncode_AddTag(pCtx, CBOR_TAG_DATE_STRING); + QCBOREncode_AddSZString(pCtx, szDate); +} + + +static inline void QCBOREncode_AddSimple(QCBOREncodeContext *pCtx, uint64_t uNum) +{ + QCBOREncode_AddType7(pCtx, 0, uNum); +} + +static inline void QCBOREncode_AddSimpleToMap(QCBOREncodeContext *pCtx, const char *szLabel, uint8_t uSimple) +{ + QCBOREncode_AddSZString(pCtx, szLabel); + QCBOREncode_AddSimple(pCtx, uSimple); +} + +static inline void QCBOREncode_AddSimpleToMapN(QCBOREncodeContext *pCtx, int nLabel, uint8_t uSimple) +{ + QCBOREncode_AddInt64(pCtx, nLabel); + QCBOREncode_AddSimple(pCtx, uSimple); +} + + +static inline void QCBOREncode_AddBool(QCBOREncodeContext *pCtx, bool b) +{ + uint8_t uSimple = CBOR_SIMPLEV_FALSE; + if(b) { + uSimple = CBOR_SIMPLEV_TRUE; + } + QCBOREncode_AddSimple(pCtx, uSimple); +} + +static inline void QCBOREncode_AddBoolToMap(QCBOREncodeContext *pCtx, const char *szLabel, bool b) +{ + QCBOREncode_AddSZString(pCtx, szLabel); + QCBOREncode_AddBool(pCtx, b); +} + +static inline void QCBOREncode_AddBoolToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, bool b) +{ + QCBOREncode_AddInt64(pCtx, nLabel); + QCBOREncode_AddBool(pCtx, b); +} + + +static inline void QCBOREncode_AddNULL(QCBOREncodeContext *pCtx) +{ + QCBOREncode_AddSimple(pCtx, CBOR_SIMPLEV_NULL); +} + +static inline void QCBOREncode_AddNULLToMap(QCBOREncodeContext *pCtx, const char *szLabel) +{ + QCBOREncode_AddSZString(pCtx, szLabel); + QCBOREncode_AddNULL(pCtx); +} + +static inline void QCBOREncode_AddNULLToMapN(QCBOREncodeContext *pCtx, int64_t nLabel) +{ + QCBOREncode_AddInt64(pCtx, nLabel); + QCBOREncode_AddNULL(pCtx); +} + + +static inline void QCBOREncode_AddUndef(QCBOREncodeContext *pCtx) +{ + QCBOREncode_AddSimple(pCtx, CBOR_SIMPLEV_UNDEF); +} + +static inline void QCBOREncode_AddUndefToMap(QCBOREncodeContext *pCtx, const char *szLabel) +{ + QCBOREncode_AddSZString(pCtx, szLabel); + QCBOREncode_AddUndef(pCtx); +} + +static inline void QCBOREncode_AddUndefToMapN(QCBOREncodeContext *pCtx, int64_t nLabel) +{ + QCBOREncode_AddInt64(pCtx, nLabel); + QCBOREncode_AddUndef(pCtx); +} + + +static inline void QCBOREncode_OpenArray(QCBOREncodeContext *pCtx) +{ + QCBOREncode_OpenMapOrArray(pCtx, CBOR_MAJOR_TYPE_ARRAY); +} + +static inline void QCBOREncode_OpenArrayInMap(QCBOREncodeContext *pCtx, const char *szLabel) +{ + QCBOREncode_AddSZString(pCtx, szLabel); + QCBOREncode_OpenArray(pCtx); +} + +static inline void QCBOREncode_OpenArrayInMapN(QCBOREncodeContext *pCtx, int64_t nLabel) +{ + QCBOREncode_AddInt64(pCtx, nLabel); + QCBOREncode_OpenArray(pCtx); +} + +static inline void QCBOREncode_CloseArray(QCBOREncodeContext *pCtx) +{ + QCBOREncode_CloseMapOrArray(pCtx, CBOR_MAJOR_TYPE_ARRAY, NULL); +} + + +static inline void QCBOREncode_OpenMap(QCBOREncodeContext *pCtx) +{ + QCBOREncode_OpenMapOrArray(pCtx, CBOR_MAJOR_TYPE_MAP); +} + +static inline void QCBOREncode_OpenMapInMap(QCBOREncodeContext *pCtx, const char *szLabel) +{ + QCBOREncode_AddSZString(pCtx, szLabel); + QCBOREncode_OpenMap(pCtx); +} + +static inline void QCBOREncode_OpenMapInMapN(QCBOREncodeContext *pCtx, int64_t nLabel) +{ + QCBOREncode_AddInt64(pCtx, nLabel); + QCBOREncode_OpenMap(pCtx); +} + +static inline void QCBOREncode_CloseMap(QCBOREncodeContext *pCtx) +{ + QCBOREncode_CloseMapOrArray(pCtx, CBOR_MAJOR_TYPE_MAP, NULL); +} + + +static inline void QCBOREncode_BstrWrap(QCBOREncodeContext *pCtx) +{ + QCBOREncode_OpenMapOrArray(pCtx, CBOR_MAJOR_TYPE_BYTE_STRING); +} + +static inline void QCBOREncode_BstrWrapInMap(QCBOREncodeContext *pCtx, const char *szLabel) +{ + QCBOREncode_AddSZString(pCtx, szLabel); + QCBOREncode_BstrWrap(pCtx); +} + +static inline void QCBOREncode_BstrWrapInMapN(QCBOREncodeContext *pCtx, int64_t nLabel) +{ + QCBOREncode_AddInt64(pCtx, nLabel); + QCBOREncode_BstrWrap(pCtx); +} + +static inline void QCBOREncode_CloseBstrWrap(QCBOREncodeContext *pCtx, UsefulBufC *pWrappedCBOR) +{ + QCBOREncode_CloseMapOrArray(pCtx, CBOR_MAJOR_TYPE_BYTE_STRING, pWrappedCBOR); +} + + +static inline void QCBOREncode_AddEncoded(QCBOREncodeContext *pCtx, UsefulBufC Encoded) +{ + QCBOREncode_AddBuffer(pCtx, CBOR_MAJOR_NONE_TYPE_RAW, Encoded); +} + +static inline void QCBOREncode_AddEncodedToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Encoded) +{ + QCBOREncode_AddSZString(pCtx, szLabel); + QCBOREncode_AddEncoded(pCtx, Encoded); +} + +static inline void QCBOREncode_AddEncodedToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Encoded) +{ + QCBOREncode_AddInt64(pCtx, nLabel); + QCBOREncode_AddEncoded(pCtx, Encoded); +} + + +/* =========================================================================== + END OF PRIVATE INLINE IMPLEMENTATION + + =========================================================================== */ + +#endif /* defined(__QCBOR__qcbor__) */ + diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/qcbor/inc/useful_buf.h b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/qcbor/inc/useful_buf.h new file mode 100644 index 0000000..dcb88b8 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/qcbor/inc/useful_buf.h @@ -0,0 +1,143 @@ +/* + * useful_buf.h + * + * Copyright 2019, Laurence Lundblade + * + * SPDX-License-Identifier: BSD-3-Clause + * + * See BSD-3-Clause license in README.mdE. + */ + + +#ifndef __USEFUL_BUF_H__ +#define __USEFUL_BUF_H__ + +#include "UsefulBuf.h" + + +/** + * \file useful_buf.h + * + * \brief This is a TF-M coding style version of UsefulBuf. + * See UsefulBuf for documentation of these functions. + */ + + +#define NULL_USEFUL_BUF_C NULLUsefulBufC + +#define NULL_USEFUL_BUF NULLUsefulBuf + + +static inline int useful_buf_c_is_null(struct useful_buf_c in) +{ + return UsefulBuf_IsNULLC(in); +} + + +static inline int useful_buf_is_null(struct useful_buf in) +{ + return UsefulBuf_IsNULL(in); +} + + +static inline int useful_buf_c_is_empty(struct useful_buf_c in) +{ + return UsefulBuf_IsEmptyC(in); +} + +static inline int useful_buf_is_empty(struct useful_buf in) +{ + return UsefulBuf_IsEmpty(in); +} + + +static inline int useful_buf_is_null_or_empty(struct useful_buf in) +{ + return UsefulBuf_IsNULLOrEmpty(in); +} + + +static inline int useful_buf_c_is_null_or_empty(struct useful_buf_c in) +{ + return UsefulBuf_IsNULLOrEmptyC(in); +} + + +static inline struct useful_buf useful_buf_unconst(struct useful_buf_c in) +{ + return UsefulBuf_Unconst(in); +} + +#define USEFUL_BUF_FROM_SZ_LITERAL UsefulBuf_FROM_SZ_LITERAL + +#define USEFUL_BUF_FROM_BYTE_ARRAY_LITERAL UsefulBuf_FROM_BYTE_ARRAY_LITERAL + +#define USEFUL_BUF_MAKE_STACK_UB UsefulBuf_MAKE_STACK_UB + +#define USEFUL_BUF_FROM_BYTE_ARRAY UsefulBuf_FROM_BYTE_ARRAY + + +static inline struct useful_buf_c useful_buf_from_sz(const char *string) +{ + return UsefulBuf_FromSZ(string); +} + +static inline struct +useful_buf_c useful_buf_copy_offset(struct useful_buf dest, + size_t offset, + struct useful_buf_c src) +{ + return UsefulBuf_CopyOffset(dest, offset, src); +} + + + +static inline struct useful_buf_c useful_buf_copy(struct useful_buf dest, + struct useful_buf_c src) +{ + return UsefulBuf_Copy(dest, src); +} + + +static inline struct useful_buf_c useful_buf_set(struct useful_buf dest, + uint8_t value) +{ + return UsefulBuf_Set(dest, value); +} + + +static inline struct useful_buf_c useful_buf_copy_ptr(struct useful_buf dest, + const void *ptr, + size_t len) +{ + return UsefulBuf_CopyPtr(dest, ptr, len); +} + + +static inline struct useful_buf_c useful_buf_head(struct useful_buf_c buf, + size_t amount) +{ + return UsefulBuf_Head(buf, amount); +} + +static inline struct useful_buf_c useful_buf_tail(struct useful_buf_c buf, + size_t amount) +{ + return UsefulBuf_Tail(buf, amount); +} + +static inline int useful_buf_compare(const struct useful_buf_c buf1, + const struct useful_buf_c buf2) +{ + return UsefulBuf_Compare(buf1, buf2); +} + +static inline size_t +useful_buf_find_bytes(const struct useful_buf_c bytes_to_search, + const struct useful_buf_c bytes_to_find) +{ + return UsefulBuf_FindBytes(bytes_to_search, bytes_to_find); +} + + +#endif /* __USEFUL_BUF_H__ */ diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/qcbor/src/UsefulBuf.c b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/qcbor/src/UsefulBuf.c new file mode 100644 index 0000000..d02708b --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/qcbor/src/UsefulBuf.c @@ -0,0 +1,330 @@ +/*============================================================================== + Copyright (c) 2016-2018, The Linux Foundation. + Copyright (c) 2018-2019, Laurence Lundblade. + All rights reserved. + SPDX-License-Identifier: BSD-3-Clause + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of The Linux Foundation nor the names of its + contributors, nor the name "Laurence Lundblade" may be used to + endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ==============================================================================*/ + +/*=================================================================================== + FILE: UsefulBuf.c + + DESCRIPTION: General purpose input and output buffers + + EDIT HISTORY FOR FILE: + + This section contains comments describing changes made to the module. + Notice that changes are listed in reverse chronological order. + + when who what, where, why + -------- ---- --------------------------------------------------- + 09/07/17 llundbla Fix critical bug in UsefulBuf_Find() -- a read off + the end of memory when the bytes to find is longer + than the bytes to search. + 06/27/17 llundbla Fix UsefulBuf_Compare() bug. Only affected comparison + for < or > for unequal length buffers. Added + UsefulBuf_Set() function. + 05/30/17 llundbla Functions for NULL UsefulBufs and const / unconst + 11/13/16 llundbla Initial Version. + + =====================================================================================*/ + +#include "UsefulBuf.h" + +#define USEFUL_OUT_BUF_MAGIC (0x0B0F) // used to catch use of uninitialized or corrupted UOBs + + +/* + Public function -- see UsefulBuf.h + */ +UsefulBufC UsefulBuf_CopyOffset(UsefulBuf Dest, size_t uOffset, const UsefulBufC Src) +{ + // Do this with subtraction so it doesn't give erroneous result if uOffset + Src.len overflows + if(uOffset > Dest.len || Src.len > Dest.len - uOffset) { // uOffset + Src.len > Dest.len + return NULLUsefulBufC; + } + + memcpy((uint8_t *)Dest.ptr + uOffset, Src.ptr, Src.len); + + return (UsefulBufC){Dest.ptr, Src.len + uOffset}; +} + + +/* + Public function -- see UsefulBuf.h + */ +int UsefulBuf_Compare(const UsefulBufC UB1, const UsefulBufC UB2) +{ + // use the comparisons rather than subtracting lengths to + // return an int instead of a size_t + if(UB1.len < UB2.len) { + return -1; + } else if (UB1.len > UB2.len) { + return 1; + } // else UB1.len == UB2.len + + return memcmp(UB1.ptr, UB2.ptr, UB1.len); +} + + + +/* + Public function -- see UsefulBuf.h + */ +size_t UsefulBuf_FindBytes(UsefulBufC BytesToSearch, UsefulBufC BytesToFind) +{ + if(BytesToSearch.len < BytesToFind.len) { + return SIZE_MAX; + } + + for(size_t uPos = 0; uPos <= BytesToSearch.len - BytesToFind.len; uPos++) { + if(!UsefulBuf_Compare((UsefulBufC){((uint8_t *)BytesToSearch.ptr) + uPos, BytesToFind.len}, BytesToFind)) { + return uPos; + } + } + + return SIZE_MAX; +} + + +/* + Public function -- see UsefulBuf.h + + Code Reviewers: THIS FUNCTION DOES POINTER MATH + */ +void UsefulOutBuf_Init(UsefulOutBuf *me, UsefulBuf Storage) +{ + me->magic = USEFUL_OUT_BUF_MAGIC; + UsefulOutBuf_Reset(me); + me->UB = Storage; + +#if 0 + // This check is off by default. + + // The following check fails on ThreadX + + // Sanity check on the pointer and size to be sure we are not + // passed a buffer that goes off the end of the address space. + // Given this test, we know that all unsigned lengths less than + // me->size are valid and won't wrap in any pointer additions + // based off of pStorage in the rest of this code. + const uintptr_t ptrM = UINTPTR_MAX - Storage.len; + if(Storage.ptr && (uintptr_t)Storage.ptr > ptrM) // Check #0 + me->err = 1; +#endif +} + + + +/* + Public function -- see UsefulBuf.h + + The core of UsefulOutBuf -- put some bytes in the buffer without writing off the end of it. + + Code Reviewers: THIS FUNCTION DOES POINTER MATH + + This function inserts the source buffer, NewData, into the destination buffer, me->UB.ptr. + + Destination is represented as: + me->UB.ptr -- start of the buffer + me->UB.len -- size of the buffer UB.ptr + me->data_len -- length of value data in UB + + Source is data: + NewData.ptr -- start of source buffer + NewData.len -- length of source buffer + + Insertion point: + uInsertionPos. + + Steps: + + 0. Corruption checks on UsefulOutBuf + + 1. Figure out if the new data will fit or not + + 2. Is insertion position in the range of valid data? + + 3. If insertion point is not at the end, slide data to the right of the insertion point to the right + + 4. Put the new data in at the insertion position. + + */ +void UsefulOutBuf_InsertUsefulBuf(UsefulOutBuf *me, UsefulBufC NewData, size_t uInsertionPos) +{ + if(me->err) { + // Already in error state. + return; + } + + /* 0. Sanity check the UsefulOutBuf structure */ + // A "counter measure". If magic number is not the right number it + // probably means me was not initialized or it was corrupted. Attackers + // can defeat this, but it is a hurdle and does good with very + // little code. + if(me->magic != USEFUL_OUT_BUF_MAGIC) { + me->err = 1; + return; // Magic number is wrong due to uninitalization or corrption + } + + // Make sure valid data is less than buffer size. This would only occur + // if there was corruption of me, but it is also part of the checks to + // be sure there is no pointer arithmatic under/overflow. + if(me->data_len > me->UB.len) { // Check #1 + me->err = 1; + return; // Offset of valid data is off the end of the UsefulOutBuf due to uninitialization or corruption + } + + /* 1. Will it fit? */ + // WillItFit() is the same as: NewData.len <= (me->size - me->data_len) + // Check #1 makes sure subtraction in RoomLeft will not wrap around + if(! UsefulOutBuf_WillItFit(me, NewData.len)) { // Check #2 + // The new data will not fit into the the buffer. + me->err = 1; + return; + } + + /* 2. Check the Insertion Position */ + // This, with Check #1, also confirms that uInsertionPos <= me->data_len + if(uInsertionPos > me->data_len) { // Check #3 + // Off the end of the valid data in the buffer. + me->err = 1; + return; + } + + /* 3. Slide existing data to the right */ + uint8_t *pSourceOfMove = ((uint8_t *)me->UB.ptr) + uInsertionPos; // PtrMath #1 + size_t uNumBytesToMove = me->data_len - uInsertionPos; // PtrMath #2 + uint8_t *pDestinationOfMove = pSourceOfMove + NewData.len; // PtrMath #3 + + if(uNumBytesToMove && me->UB.ptr) { + // To know memmove won't go off end of destination, see PtrMath #4 + memmove(pDestinationOfMove, pSourceOfMove, uNumBytesToMove); + } + + /* 4. Put the new data in */ + uint8_t *pInsertionPoint = ((uint8_t *)me->UB.ptr) + uInsertionPos; // PtrMath #5 + if(me->UB.ptr) { + // To know memmove won't go off end of destination, see PtrMath #6 + memmove(pInsertionPoint, NewData.ptr, NewData.len); + } + me->data_len += NewData.len ; +} + + +/* + Rationale that describes why the above pointer math is safe + + PtrMath #1 will never wrap around over because + Check #0 in UsefulOutBuf_Init makes sure me->UB.ptr + me->UB.len doesn't wrap + Check #1 makes sure me->data_len is less than me->UB.len + Check #3 makes sure uInsertionPos is less than me->data_len + + PtrMath #2 will never wrap around under because + Check #3 makes sure uInsertionPos is less than me->data_len + + PtrMath #3 will never wrap around over because todo + PtrMath #1 is checked resulting in pSourceOfMove being between me->UB.ptr and a maximum valid ptr + Check #2 that NewData.len will fit + + PtrMath #4 will never wrap under because + Calculation for extent or memmove is uRoomInDestination = me->UB.len - (uInsertionPos + NewData.len) + Check #3 makes sure uInsertionPos is less than me->data_len + Check #3 allows Check #2 to be refactored as NewData.Len > (me->size - uInsertionPos) + This algebraically rearranges to me->size > uInsertionPos + NewData.len + + PtrMath #5 is exactly the same as PtrMath #1 + + PtrMath #6 will never wrap under because + Calculation for extent of memove is uRoomInDestination = me->UB.len - uInsertionPos; + Check #1 makes sure me->data_len is less than me->size + Check #3 makes sure uInsertionPos is less than me->data_len + */ + + +/* + Public function -- see UsefulBuf.h + */ +UsefulBufC UsefulOutBuf_OutUBuf(UsefulOutBuf *me) +{ + if(me->err) { + return NULLUsefulBufC; + } + + if(me->magic != USEFUL_OUT_BUF_MAGIC) { + me->err = 1; + return NULLUsefulBufC; + } + + return (UsefulBufC){me->UB.ptr,me->data_len}; +} + + +/* + Public function -- see UsefulBuf.h + + Copy out the data accumulated in to the output buffer. + */ +UsefulBufC UsefulOutBuf_CopyOut(UsefulOutBuf *me, UsefulBuf pDest) +{ + const UsefulBufC Tmp = UsefulOutBuf_OutUBuf(me); + if(UsefulBuf_IsNULLC(Tmp)) { + return NULLUsefulBufC; + } + return UsefulBuf_Copy(pDest, Tmp); +} + + + + +/* + Public function -- see UsefulBuf.h + + The core of UsefulInputBuf -- consume some bytes without going off the end of the buffer. + + Code Reviewers: THIS FUNCTION DOES POINTER MATH + */ +const void * UsefulInputBuf_GetBytes(UsefulInputBuf *me, size_t uAmount) +{ + // Already in error state. Do nothing. + if(me->err) { + return NULL; + } + + if(!UsefulInputBuf_BytesAvailable(me, uAmount)) { + // The number of bytes asked for at current position are more than available + me->err = 1; + return NULL; + } + + // This is going to succeed + const void * const result = ((uint8_t *)me->UB.ptr) + me->cursor; + me->cursor += uAmount; // this will not overflow because of check using UsefulInputBuf_BytesAvailable() + return result; +} + diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/qcbor/src/ieee754.c b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/qcbor/src/ieee754.c new file mode 100644 index 0000000..6fdfda8 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/qcbor/src/ieee754.c @@ -0,0 +1,497 @@ +/*============================================================================== + ieee754.c -- floating point conversion between half, double and single precision + + Copyright (c) 2018-2019, Laurence Lundblade. All rights reserved. + + SPDX-License-Identifier: BSD-3-Clause + + See BSD-3-Clause license in README.md + + Created on 7/23/18 + ==============================================================================*/ + +#include "ieee754.h" +#include // For memcpy() + + +/* + This code is written for clarity and verifiability, not for size, on the assumption + that the optimizer will do a good job. The LLVM optimizer, -Os, does seem to do the + job and the resulting object code is smaller from combining code for the many different + cases (normal, subnormal, infinity, zero...) for the conversions. + + Dead stripping is also really helpful to get code size down when floating point + encoding is not needed. + + This code works solely using shifts and masks and thus has no dependency on + any math libraries. It can even work if the CPU doesn't have any floating + point support, though that isn't the most useful thing to do. + + The memcpy() dependency is only for CopyFloatToUint32() and friends which only + is needed to avoid type punning when converting the actual float bits to + an unsigned value so the bit shifts and masks can work. + */ + +/* + The references used to write this code: + + - IEEE 754-2008, particularly section 3.6 and 6.2.1 + + - https://en.wikipedia.org/wiki/IEEE_754 and subordinate pages + + - https://stackoverflow.com/questions/19800415/why-does-ieee-754-reserve-so-many-nan-values + */ + + +// ----- Half Precsion ----------- +#define HALF_NUM_SIGNIFICAND_BITS (10) +#define HALF_NUM_EXPONENT_BITS (5) +#define HALF_NUM_SIGN_BITS (1) + +#define HALF_SIGNIFICAND_SHIFT (0) +#define HALF_EXPONENT_SHIFT (HALF_NUM_SIGNIFICAND_BITS) +#define HALF_SIGN_SHIFT (HALF_NUM_SIGNIFICAND_BITS + HALF_NUM_EXPONENT_BITS) + +#define HALF_SIGNIFICAND_MASK (0x3ff) // The lower 10 bits // 0x03ff +#define HALF_EXPONENT_MASK (0x1f << HALF_EXPONENT_SHIFT) // 0x7c00 5 bits of exponent +#define HALF_SIGN_MASK (0x01 << HALF_SIGN_SHIFT) // // 0x80001 bit of sign +#define HALF_QUIET_NAN_BIT (0x01 << (HALF_NUM_SIGNIFICAND_BITS-1)) // 0x0200 + +/* Biased Biased Unbiased Use + 0x00 0 -15 0 and subnormal + 0x01 1 -14 Smallest normal exponent + 0x1e 30 15 Largest normal exponent + 0x1F 31 16 NaN and Infinity */ +#define HALF_EXPONENT_BIAS (15) +#define HALF_EXPONENT_MAX (HALF_EXPONENT_BIAS) // 15 Unbiased +#define HALF_EXPONENT_MIN (-HALF_EXPONENT_BIAS+1) // -14 Unbiased +#define HALF_EXPONENT_ZERO (-HALF_EXPONENT_BIAS) // -15 Unbiased +#define HALF_EXPONENT_INF_OR_NAN (HALF_EXPONENT_BIAS+1) // 16 Unbiased + + +// ------ Single Precision -------- +#define SINGLE_NUM_SIGNIFICAND_BITS (23) +#define SINGLE_NUM_EXPONENT_BITS (8) +#define SINGLE_NUM_SIGN_BITS (1) + +#define SINGLE_SIGNIFICAND_SHIFT (0) +#define SINGLE_EXPONENT_SHIFT (SINGLE_NUM_SIGNIFICAND_BITS) +#define SINGLE_SIGN_SHIFT (SINGLE_NUM_SIGNIFICAND_BITS + SINGLE_NUM_EXPONENT_BITS) + +#define SINGLE_SIGNIFICAND_MASK (0x7fffffUL) // The lower 23 bits +#define SINGLE_EXPONENT_MASK (0xffUL << SINGLE_EXPONENT_SHIFT) // 8 bits of exponent +#define SINGLE_SIGN_MASK (0x01UL << SINGLE_SIGN_SHIFT) // 1 bit of sign +#define SINGLE_QUIET_NAN_BIT (0x01UL << (SINGLE_NUM_SIGNIFICAND_BITS-1)) + +/* Biased Biased Unbiased Use + 0x0000 0 -127 0 and subnormal + 0x0001 1 -126 Smallest normal exponent + 0x7f 127 0 1 + 0xfe 254 127 Largest normal exponent + 0xff 255 128 NaN and Infinity */ +#define SINGLE_EXPONENT_BIAS (127) +#define SINGLE_EXPONENT_MAX (SINGLE_EXPONENT_BIAS) // 127 unbiased +#define SINGLE_EXPONENT_MIN (-SINGLE_EXPONENT_BIAS+1) // -126 unbiased +#define SINGLE_EXPONENT_ZERO (-SINGLE_EXPONENT_BIAS) // -127 unbiased +#define SINGLE_EXPONENT_INF_OR_NAN (SINGLE_EXPONENT_BIAS+1) // 128 unbiased + + +// --------- Double Precision ---------- +#define DOUBLE_NUM_SIGNIFICAND_BITS (52) +#define DOUBLE_NUM_EXPONENT_BITS (11) +#define DOUBLE_NUM_SIGN_BITS (1) + +#define DOUBLE_SIGNIFICAND_SHIFT (0) +#define DOUBLE_EXPONENT_SHIFT (DOUBLE_NUM_SIGNIFICAND_BITS) +#define DOUBLE_SIGN_SHIFT (DOUBLE_NUM_SIGNIFICAND_BITS + DOUBLE_NUM_EXPONENT_BITS) + +#define DOUBLE_SIGNIFICAND_MASK (0xfffffffffffffULL) // The lower 52 bits +#define DOUBLE_EXPONENT_MASK (0x7ffULL << DOUBLE_EXPONENT_SHIFT) // 11 bits of exponent +#define DOUBLE_SIGN_MASK (0x01ULL << DOUBLE_SIGN_SHIFT) // 1 bit of sign +#define DOUBLE_QUIET_NAN_BIT (0x01ULL << (DOUBLE_NUM_SIGNIFICAND_BITS-1)) + + +/* Biased Biased Unbiased Use + 0x00000000 0 -1023 0 and subnormal + 0x00000001 1 -1022 Smallest normal exponent + 0x000007fe 2046 1023 Largest normal exponent + 0x000007ff 2047 1024 NaN and Infinity */ +#define DOUBLE_EXPONENT_BIAS (1023) +#define DOUBLE_EXPONENT_MAX (DOUBLE_EXPONENT_BIAS) // unbiased +#define DOUBLE_EXPONENT_MIN (-DOUBLE_EXPONENT_BIAS+1) // unbiased +#define DOUBLE_EXPONENT_ZERO (-DOUBLE_EXPONENT_BIAS) // unbiased +#define DOUBLE_EXPONENT_INF_OR_NAN (DOUBLE_EXPONENT_BIAS+1) // unbiased + + + +/* + Convenient functions to avoid type punning, compiler warnings and such + The optimizer reduces them to a simple assignment. + This is a crusty corner of C. It shouldn't be this hard. + + These are also in UsefulBuf.h under a different name. They are copied + here to avoid a dependency on UsefulBuf.h. There is no + object code size impact because these always optimze down to a + simple assignment. + */ +static inline uint32_t CopyFloatToUint32(float f) +{ + uint32_t u32; + memcpy(&u32, &f, sizeof(uint32_t)); + return u32; +} + +static inline uint64_t CopyDoubleToUint64(double d) +{ + uint64_t u64; + memcpy(&u64, &d, sizeof(uint64_t)); + return u64; +} + +static inline float CopyUint32ToFloat(uint32_t u32) +{ + float f; + memcpy(&f, &u32, sizeof(uint32_t)); + return f; +} + +static inline double CopyUint64ToDouble(uint64_t u64) +{ + double d; + memcpy(&d, &u64, sizeof(uint64_t)); + return d; +} + + +// Public function; see ieee754.h +uint16_t IEEE754_FloatToHalf(float f) +{ + // Pull the three parts out of the single-precision float + const uint32_t uSingle = CopyFloatToUint32(f); + const int32_t nSingleUnbiasedExponent = ((uSingle & SINGLE_EXPONENT_MASK) >> SINGLE_EXPONENT_SHIFT) - SINGLE_EXPONENT_BIAS; + const uint32_t uSingleSign = (uSingle & SINGLE_SIGN_MASK) >> SINGLE_SIGN_SHIFT; + const uint32_t uSingleSignificand = uSingle & SINGLE_SIGNIFICAND_MASK; + + + // Now convert the three parts to half-precision. + uint16_t uHalfSign, uHalfSignificand, uHalfBiasedExponent; + if(nSingleUnbiasedExponent == SINGLE_EXPONENT_INF_OR_NAN) { + // +/- Infinity and NaNs -- single biased exponent is 0xff + uHalfBiasedExponent = HALF_EXPONENT_INF_OR_NAN + HALF_EXPONENT_BIAS; + if(!uSingleSignificand) { + // Infinity + uHalfSignificand = 0; + } else { + // Copy the LBSs of the NaN payload that will fit from the single to the half + uHalfSignificand = uSingleSignificand & (HALF_SIGNIFICAND_MASK & ~HALF_QUIET_NAN_BIT); + if(uSingleSignificand & SINGLE_QUIET_NAN_BIT) { + // It's a qNaN; copy the qNaN bit + uHalfSignificand |= HALF_QUIET_NAN_BIT; + } else { + // It's a sNaN; make sure the significand is not zero so it stays a NaN + // This is needed because not all significand bits are copied from single + if(!uHalfSignificand) { + // Set the LSB. This is what wikipedia shows for sNAN. + uHalfSignificand |= 0x01; + } + } + } + } else if(nSingleUnbiasedExponent == SINGLE_EXPONENT_ZERO) { + // 0 or a subnormal number -- singled biased exponent is 0 + uHalfBiasedExponent = 0; + uHalfSignificand = 0; // Any subnormal single will be too small to express as a half precision + } else if(nSingleUnbiasedExponent > HALF_EXPONENT_MAX) { + // Exponent is too large to express in half-precision; round up to infinity + uHalfBiasedExponent = HALF_EXPONENT_INF_OR_NAN + HALF_EXPONENT_BIAS; + uHalfSignificand = 0; + } else if(nSingleUnbiasedExponent < HALF_EXPONENT_MIN) { + // Exponent is too small to express in half-precision normal; make it a half-precision subnormal + uHalfBiasedExponent = (uint16_t)(HALF_EXPONENT_ZERO + HALF_EXPONENT_BIAS); + // Difference between single normal exponent and the base exponent of a half subnormal + const uint32_t nExpDiff = -(nSingleUnbiasedExponent - HALF_EXPONENT_MIN); + // Also have to shift the significand by the difference in number of bits between a single and a half significand + const int32_t nSignificandBitsDiff = SINGLE_NUM_SIGNIFICAND_BITS - HALF_NUM_SIGNIFICAND_BITS; + // Add in the 1 that is implied in the significand of a normal number; it needs to be present in a subnormal + const uint32_t uSingleSignificandSubnormal = uSingleSignificand + (0x01L << SINGLE_NUM_SIGNIFICAND_BITS); + uHalfSignificand = uSingleSignificandSubnormal >> (nExpDiff + nSignificandBitsDiff); + } else { + // The normal case + uHalfBiasedExponent = nSingleUnbiasedExponent + HALF_EXPONENT_BIAS; + uHalfSignificand = uSingleSignificand >> (SINGLE_NUM_SIGNIFICAND_BITS - HALF_NUM_SIGNIFICAND_BITS); + } + uHalfSign = uSingleSign; + + // Put the 3 values in the right place for a half precision + const uint16_t uHalfPrecision = uHalfSignificand | + (uHalfBiasedExponent << HALF_EXPONENT_SHIFT) | + (uHalfSign << HALF_SIGN_SHIFT); + return uHalfPrecision; +} + + +// Public function; see ieee754.h +uint16_t IEEE754_DoubleToHalf(double d) +{ + // Pull the three parts out of the double-precision float + const uint64_t uDouble = CopyDoubleToUint64(d); + const int64_t nDoubleUnbiasedExponent = ((uDouble & DOUBLE_EXPONENT_MASK) >> DOUBLE_EXPONENT_SHIFT) - DOUBLE_EXPONENT_BIAS; + const uint64_t uDoubleSign = (uDouble & DOUBLE_SIGN_MASK) >> DOUBLE_SIGN_SHIFT; + const uint64_t uDoubleSignificand = uDouble & DOUBLE_SIGNIFICAND_MASK; + + + // Now convert the three parts to half-precision. + uint16_t uHalfSign, uHalfSignificand, uHalfBiasedExponent; + if(nDoubleUnbiasedExponent == DOUBLE_EXPONENT_INF_OR_NAN) { + // +/- Infinity and NaNs -- single biased exponent is 0xff + uHalfBiasedExponent = HALF_EXPONENT_INF_OR_NAN + HALF_EXPONENT_BIAS; + if(!uDoubleSignificand) { + // Infinity + uHalfSignificand = 0; + } else { + // Copy the LBSs of the NaN payload that will fit from the double to the half + uHalfSignificand = uDoubleSignificand & (HALF_SIGNIFICAND_MASK & ~HALF_QUIET_NAN_BIT); + if(uDoubleSignificand & DOUBLE_QUIET_NAN_BIT) { + // It's a qNaN; copy the qNaN bit + uHalfSignificand |= HALF_QUIET_NAN_BIT; + } else { + // It's an sNaN; make sure the significand is not zero so it stays a NaN + // This is needed because not all significand bits are copied from single + if(!uHalfSignificand) { + // Set the LSB. This is what wikipedia shows for sNAN. + uHalfSignificand |= 0x01; + } + } + } + } else if(nDoubleUnbiasedExponent == DOUBLE_EXPONENT_ZERO) { + // 0 or a subnormal number -- double biased exponent is 0 + uHalfBiasedExponent = 0; + uHalfSignificand = 0; // Any subnormal single will be too small to express as a half precision; TODO, is this really true? + } else if(nDoubleUnbiasedExponent > HALF_EXPONENT_MAX) { + // Exponent is too large to express in half-precision; round up to infinity; TODO, is this really true? + uHalfBiasedExponent = HALF_EXPONENT_INF_OR_NAN + HALF_EXPONENT_BIAS; + uHalfSignificand = 0; + } else if(nDoubleUnbiasedExponent < HALF_EXPONENT_MIN) { + // Exponent is too small to express in half-precision; round down to zero + uHalfBiasedExponent = (uint16_t)(HALF_EXPONENT_ZERO + HALF_EXPONENT_BIAS); + // Difference between double normal exponent and the base exponent of a half subnormal + const uint64_t nExpDiff = -(nDoubleUnbiasedExponent - HALF_EXPONENT_MIN); + // Also have to shift the significand by the difference in number of bits between a double and a half significand + const int64_t nSignificandBitsDiff = DOUBLE_NUM_SIGNIFICAND_BITS - HALF_NUM_SIGNIFICAND_BITS; + // Add in the 1 that is implied in the significand of a normal number; it needs to be present in a subnormal + const uint64_t uDoubleSignificandSubnormal = uDoubleSignificand + (0x01ULL << DOUBLE_NUM_SIGNIFICAND_BITS); + uHalfSignificand = uDoubleSignificandSubnormal >> (nExpDiff + nSignificandBitsDiff); + } else { + // The normal case + uHalfBiasedExponent = nDoubleUnbiasedExponent + HALF_EXPONENT_BIAS; + uHalfSignificand = uDoubleSignificand >> (DOUBLE_NUM_SIGNIFICAND_BITS - HALF_NUM_SIGNIFICAND_BITS); + } + uHalfSign = uDoubleSign; + + + // Put the 3 values in the right place for a half precision + const uint16_t uHalfPrecision = uHalfSignificand | + (uHalfBiasedExponent << HALF_EXPONENT_SHIFT) | + (uHalfSign << HALF_SIGN_SHIFT); + return uHalfPrecision; +} + + +// Public function; see ieee754.h +float IEEE754_HalfToFloat(uint16_t uHalfPrecision) +{ + // Pull out the three parts of the half-precision float + const uint16_t uHalfSignificand = uHalfPrecision & HALF_SIGNIFICAND_MASK; + const int16_t nHalfUnBiasedExponent = ((uHalfPrecision & HALF_EXPONENT_MASK) >> HALF_EXPONENT_SHIFT) - HALF_EXPONENT_BIAS; + const uint16_t uHalfSign = (uHalfPrecision & HALF_SIGN_MASK) >> HALF_SIGN_SHIFT; + + + // Make the three parts of the single-precision number + uint32_t uSingleSignificand, uSingleSign, uSingleBiasedExponent; + if(nHalfUnBiasedExponent == HALF_EXPONENT_ZERO) { + // 0 or subnormal + if(uHalfSignificand) { + // Subnormal case + uSingleBiasedExponent = -HALF_EXPONENT_BIAS + SINGLE_EXPONENT_BIAS +1; + // A half-precision subnormal can always be converted to a normal single-precision float because the ranges line up + uSingleSignificand = uHalfSignificand; + // Shift bits from right of the decimal to left, reducing the exponent by 1 each time + do { + uSingleSignificand <<= 1; + uSingleBiasedExponent--; + } while ((uSingleSignificand & 0x400) == 0); + uSingleSignificand &= HALF_SIGNIFICAND_MASK; + uSingleSignificand <<= (SINGLE_NUM_SIGNIFICAND_BITS - HALF_NUM_SIGNIFICAND_BITS); + } else { + // Just zero + uSingleBiasedExponent = SINGLE_EXPONENT_ZERO + SINGLE_EXPONENT_BIAS; + uSingleSignificand = 0; + } + } else if(nHalfUnBiasedExponent == HALF_EXPONENT_INF_OR_NAN) { + // NaN or Inifinity + uSingleBiasedExponent = SINGLE_EXPONENT_INF_OR_NAN + SINGLE_EXPONENT_BIAS; + if(uHalfSignificand) { + // NaN + // First preserve the NaN payload from half to single + uSingleSignificand = uHalfSignificand & ~HALF_QUIET_NAN_BIT; + if(uHalfSignificand & HALF_QUIET_NAN_BIT) { + // Next, set qNaN if needed since half qNaN bit is not copied above + uSingleSignificand |= SINGLE_QUIET_NAN_BIT; + } + } else { + // Infinity + uSingleSignificand = 0; + } + } else { + // Normal number + uSingleBiasedExponent = nHalfUnBiasedExponent + SINGLE_EXPONENT_BIAS; + uSingleSignificand = uHalfSignificand << (SINGLE_NUM_SIGNIFICAND_BITS - HALF_NUM_SIGNIFICAND_BITS); + } + uSingleSign = uHalfSign; + + + // Shift the three parts of the single precision into place + const uint32_t uSinglePrecision = uSingleSignificand | + (uSingleBiasedExponent << SINGLE_EXPONENT_SHIFT) | + (uSingleSign << SINGLE_SIGN_SHIFT); + + return CopyUint32ToFloat(uSinglePrecision); +} + + +// Public function; see ieee754.h +double IEEE754_HalfToDouble(uint16_t uHalfPrecision) +{ + // Pull out the three parts of the half-precision float + const uint16_t uHalfSignificand = uHalfPrecision & HALF_SIGNIFICAND_MASK; + const int16_t nHalfUnBiasedExponent = ((uHalfPrecision & HALF_EXPONENT_MASK) >> HALF_EXPONENT_SHIFT) - HALF_EXPONENT_BIAS; + const uint16_t uHalfSign = (uHalfPrecision & HALF_SIGN_MASK) >> HALF_SIGN_SHIFT; + + + // Make the three parts of hte single-precision number + uint64_t uDoubleSignificand, uDoubleSign, uDoubleBiasedExponent; + if(nHalfUnBiasedExponent == HALF_EXPONENT_ZERO) { + // 0 or subnormal + uDoubleBiasedExponent = DOUBLE_EXPONENT_ZERO + DOUBLE_EXPONENT_BIAS; + if(uHalfSignificand) { + // Subnormal case + uDoubleBiasedExponent = -HALF_EXPONENT_BIAS + DOUBLE_EXPONENT_BIAS +1; + // A half-precision subnormal can always be converted to a normal double-precision float because the ranges line up + uDoubleSignificand = uHalfSignificand; + // Shift bits from right of the decimal to left, reducing the exponent by 1 each time + do { + uDoubleSignificand <<= 1; + uDoubleBiasedExponent--; + } while ((uDoubleSignificand & 0x400) == 0); + uDoubleSignificand &= HALF_SIGNIFICAND_MASK; + uDoubleSignificand <<= (DOUBLE_NUM_SIGNIFICAND_BITS - HALF_NUM_SIGNIFICAND_BITS); + } else { + // Just zero + uDoubleSignificand = 0; + } + } else if(nHalfUnBiasedExponent == HALF_EXPONENT_INF_OR_NAN) { + // NaN or Inifinity + uDoubleBiasedExponent = DOUBLE_EXPONENT_INF_OR_NAN + DOUBLE_EXPONENT_BIAS; + if(uHalfSignificand) { + // NaN + // First preserve the NaN payload from half to single + uDoubleSignificand = uHalfSignificand & ~HALF_QUIET_NAN_BIT; + if(uHalfSignificand & HALF_QUIET_NAN_BIT) { + // Next, set qNaN if needed since half qNaN bit is not copied above + uDoubleSignificand |= DOUBLE_QUIET_NAN_BIT; + } + } else { + // Infinity + uDoubleSignificand = 0; + } + } else { + // Normal number + uDoubleBiasedExponent = nHalfUnBiasedExponent + DOUBLE_EXPONENT_BIAS; + uDoubleSignificand = (uint64_t)uHalfSignificand << (DOUBLE_NUM_SIGNIFICAND_BITS - HALF_NUM_SIGNIFICAND_BITS); + } + uDoubleSign = uHalfSign; + + + // Shift the 3 parts into place as a double-precision + const uint64_t uDouble = uDoubleSignificand | + (uDoubleBiasedExponent << DOUBLE_EXPONENT_SHIFT) | + (uDoubleSign << DOUBLE_SIGN_SHIFT); + return CopyUint64ToDouble(uDouble); +} + + +// Public function; see ieee754.h +IEEE754_union IEEE754_FloatToSmallest(float f) +{ + IEEE754_union result; + + // Pull the neeed two parts out of the single-precision float + const uint32_t uSingle = CopyFloatToUint32(f); + const int32_t nSingleExponent = ((uSingle & SINGLE_EXPONENT_MASK) >> SINGLE_EXPONENT_SHIFT) - SINGLE_EXPONENT_BIAS; + const uint32_t uSingleSignificand = uSingle & SINGLE_SIGNIFICAND_MASK; + + // Bit mask that is the significand bits that would be lost when converting + // from single-precision to half-precision + const uint64_t uDroppedSingleBits = SINGLE_SIGNIFICAND_MASK >> HALF_NUM_SIGNIFICAND_BITS; + + // Optimizer will re organize so there is only one call to IEEE754_FloatToHalf() + if(uSingle == 0) { + // Value is 0.0000, not a a subnormal + result.uSize = IEEE754_UNION_IS_HALF; + result.uValue = IEEE754_FloatToHalf(f); + } else if(nSingleExponent == SINGLE_EXPONENT_INF_OR_NAN) { + // NaN, +/- infinity + result.uSize = IEEE754_UNION_IS_HALF; + result.uValue = IEEE754_FloatToHalf(f); + } else if((nSingleExponent >= HALF_EXPONENT_MIN) && nSingleExponent <= HALF_EXPONENT_MAX && (!(uSingleSignificand & uDroppedSingleBits))) { + // Normal number in exponent range and precision won't be lost + result.uSize = IEEE754_UNION_IS_HALF; + result.uValue = IEEE754_FloatToHalf(f); + } else { + // Subnormal, exponent out of range, or precision will be lost + result.uSize = IEEE754_UNION_IS_SINGLE; + result.uValue = uSingle; + } + + return result; +} + +// Public function; see ieee754.h +IEEE754_union IEEE754_DoubleToSmallestInternal(double d, int bAllowHalfPrecision) +{ + IEEE754_union result; + + // Pull the needed two parts out of the double-precision float + const uint64_t uDouble = CopyDoubleToUint64(d); + const int64_t nDoubleExponent = ((uDouble & DOUBLE_EXPONENT_MASK) >> DOUBLE_EXPONENT_SHIFT) - DOUBLE_EXPONENT_BIAS; + const uint64_t uDoubleSignificand = uDouble & DOUBLE_SIGNIFICAND_MASK; + + // Masks to check whether dropped significand bits are zero or not + const uint64_t uDroppedDoubleBits = DOUBLE_SIGNIFICAND_MASK >> HALF_NUM_SIGNIFICAND_BITS; + const uint64_t uDroppedSingleBits = DOUBLE_SIGNIFICAND_MASK >> SINGLE_NUM_SIGNIFICAND_BITS; + + // The various cases + if(d == 0.0) { // Take care of positive and negative zero + // Value is 0.0000, not a a subnormal + result.uSize = IEEE754_UNION_IS_HALF; + result.uValue = IEEE754_DoubleToHalf(d); + } else if(nDoubleExponent == DOUBLE_EXPONENT_INF_OR_NAN) { + // NaN, +/- infinity + result.uSize = IEEE754_UNION_IS_HALF; + result.uValue = IEEE754_DoubleToHalf(d); + } else if(bAllowHalfPrecision && (nDoubleExponent >= HALF_EXPONENT_MIN) && nDoubleExponent <= HALF_EXPONENT_MAX && (!(uDoubleSignificand & uDroppedDoubleBits))) { + // Can convert to half without precision loss + result.uSize = IEEE754_UNION_IS_HALF; + result.uValue = IEEE754_DoubleToHalf(d); + } else if((nDoubleExponent >= SINGLE_EXPONENT_MIN) && nDoubleExponent <= SINGLE_EXPONENT_MAX && (!(uDoubleSignificand & uDroppedSingleBits))) { + // Can convert to single without precision loss + result.uSize = IEEE754_UNION_IS_SINGLE; + result.uValue = CopyFloatToUint32((float)d); + } else { + // Can't convert without precision loss + result.uSize = IEEE754_UNION_IS_DOUBLE; + result.uValue = uDouble; + } + + return result; +} + diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/qcbor/src/ieee754.h b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/qcbor/src/ieee754.h new file mode 100644 index 0000000..2530f98 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/qcbor/src/ieee754.h @@ -0,0 +1,168 @@ +/*============================================================================== + ieee754.c -- floating point conversion between half, double and single precision + + Copyright (c) 2018-2019, Laurence Lundblade. All rights reserved. + + SPDX-License-Identifier: BSD-3-Clause + + See BSD-3-Clause license in README.md + + Created on 7/23/18 + ==============================================================================*/ + +#ifndef ieee754_h +#define ieee754_h + +#include + + + +/* + General comments + + This is a complete in that it handles all conversion cases + including +/- infinity, +/- zero, subnormal numbers, qNaN, sNaN + and NaN payloads. + + This confirms to IEEE 754-2008, but note that this doesn't + specify conversions, just the encodings. + + NaN payloads are preserved with alignment on the LSB. The + qNaN bit is handled differently and explicity copied. It + is always the MSB of the significand. The NaN payload MSBs + (except the qNaN bit) are truncated when going from + double or single to half. + + TODO: what does the C cast do with NaN payloads from + double to single? + + + + */ + +/* + Most simply just explicilty encode the type you want, single or double. + This works easily everywhere since standard C supports both + these types and so does qcbor. This encoder also supports + half precision and there's a few ways to use it to encode + floating point numbers in less space. + + Without losing precision, you can encode a single or double + such that the special values of 0, NaN and Infinity encode + as half-precision. This CBOR decodoer and most others + should handle this properly. + + If you don't mind losing precision, then you can use half-precision. + One way to do this is to set up your environment to use + ___fp_16. Some compilers and CPUs support it even though it is not + standard C. What is nice about this is that your program + will use less memory and floating point operations like + multiplying, adding and such will be faster. + + Another way to make use of half-precision is to represent + the values in your program as single or double, but encode + them in CBOR as half-precision. This cuts the size + of the encoded messages by 2 or 4, but doesn't reduce + memory needs or speed because you are still using + single or double in your code. + + + encode: + - float as float + - double as double + - half as half + - float as half_precision, for environments that don't support a half-precision type + - double as half_precision, for environments that don't support a half-precision type + - float with NaN, Infinity and 0 as half + - double with NaN, Infinity and 0 as half + + + + + */ + + + +/* + Convert single precision float to half-precision float. + Precision and NaN payload bits will be lost. Too large + values will round up to infinity and too small to zero. + */ +uint16_t IEEE754_FloatToHalf(float f); + + +/* + Convert half precision float to single precision float. + This is a loss-less conversion. + */ +float IEEE754_HalfToFloat(uint16_t uHalfPrecision); + + +/* + Convert double precision float to half-precision float. + Precision and NaN payload bits will be lost. Too large + values will round up to infinity and too small to zero. + */ +uint16_t IEEE754_DoubleToHalf(double d); + + +/* + Convert half precision float to double precision float. + This is a loss-less conversion. + */ +double IEEE754_HalfToDouble(uint16_t uHalfPrecision); + + + +// Both tags the value and gives the size +#define IEEE754_UNION_IS_HALF 2 +#define IEEE754_UNION_IS_SINGLE 4 +#define IEEE754_UNION_IS_DOUBLE 8 + +typedef struct { + uint8_t uSize; // One of IEEE754_IS_xxxx + uint64_t uValue; +} IEEE754_union; + + +/* + Converts double-precision to single-precision or half-precision if possible without + loss of precisions. If not, leaves it as a double. Only converts to single-precision + unless bAllowHalfPrecision is set. + */ +IEEE754_union IEEE754_DoubleToSmallestInternal(double d, int bAllowHalfPrecision); + +/* + Converts double-precision to single-precision if possible without + loss of precision. If not, leaves it as a double. + */ +static inline IEEE754_union IEEE754_DoubleToSmall(double d) +{ + return IEEE754_DoubleToSmallestInternal(d, 0); +} + + +/* + Converts double-precision to single-precision or half-precision if possible without + loss of precisions. If not, leaves it as a double. + */ +static inline IEEE754_union IEEE754_DoubleToSmallest(double d) +{ + return IEEE754_DoubleToSmallestInternal(d, 1); +} + +/* + Converts single-precision to half-precision if possible without + loss of precision. If not leaves as single-precision. + */ +IEEE754_union IEEE754_FloatToSmallest(float f); + + +#endif /* ieee754_h */ + + + + + + + diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/qcbor/src/qcbor_decode.c b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/qcbor/src/qcbor_decode.c new file mode 100644 index 0000000..2cfb130 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/qcbor/src/qcbor_decode.c @@ -0,0 +1,1320 @@ +/*============================================================================== + Copyright (c) 2016-2018, The Linux Foundation. + Copyright (c) 2018-2019, Laurence Lundblade. + All rights reserved. + SPDX-License-Identifier: BSD-3-Clause + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of The Linux Foundation nor the names of its + contributors, nor the name "Laurence Lundblade" may be used to + endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ==============================================================================*/ + +/*=================================================================================== + FILE: qcbor_decode.c + + DESCRIPTION: This file contains the implementation of QCBOR. + + EDIT HISTORY FOR FILE: + + This section contains comments describing changes made to the module. + Notice that changes are listed in reverse chronological order. + + when who what, where, why + -------- ---- --------------------------------------------------- + 01/10/19 llundblade Clever type and argument decoder is 250 bytes smaller + 11/9/18 llundblade Error codes are now enums. + 11/2/18 llundblade Simplify float decoding and align with preferred + float encoding + 10/31/18 llundblade Switch to one license that is almost BSD-3. + 10/28/18 llundblade Reworked tag decoding + 10/15/18 llundblade Indefinite length maps and arrays supported + 10/8/18 llundblade Indefinite length strings supported + 02/04/17 llundbla Work on CPUs that don's require pointer alignment + by making use of changes in UsefulBuf + 03/01/17 llundbla More data types; decoding improvements and fixes + 11/13/16 llundbla Integrate most TZ changes back into github version. + 09/30/16 gkanike Porting to TZ. + 03/15/16 llundbla Initial Version. + + =====================================================================================*/ + +#include "qcbor.h" +#include "ieee754.h" + + +/* + This casts away the const-ness of a pointer, usually so it can be + freed or realloced. + */ +#define UNCONST_POINTER(ptr) ((void *)(ptr)) + + +/* + Collection of functions to track the map/array nesting for decoding + */ + +inline static int IsMapOrArray(uint8_t uDataType) +{ + return uDataType == QCBOR_TYPE_MAP || uDataType == QCBOR_TYPE_ARRAY; +} + +inline static int DecodeNesting_IsNested(const QCBORDecodeNesting *pNesting) +{ + return pNesting->pCurrent != &(pNesting->pMapsAndArrays[0]); +} + +inline static int DecodeNesting_IsIndefiniteLength(const QCBORDecodeNesting *pNesting) +{ + return pNesting->pCurrent->uCount == UINT16_MAX; +} + +inline static uint8_t DecodeNesting_GetLevel(QCBORDecodeNesting *pNesting) +{ + return pNesting->pCurrent - &(pNesting->pMapsAndArrays[0]); +} + +inline static int DecodeNesting_TypeIsMap(const QCBORDecodeNesting *pNesting) +{ + if(!DecodeNesting_IsNested(pNesting)) { + return 0; + } + + return CBOR_MAJOR_TYPE_MAP == pNesting->pCurrent->uMajorType; +} + +// Process a break. This will either ascend the nesting or error out +inline static QCBORError DecodeNesting_BreakAscend(QCBORDecodeNesting *pNesting) +{ + // breaks must always occur when there is nesting + if(!DecodeNesting_IsNested(pNesting)) { + return QCBOR_ERR_BAD_BREAK; + } + + // breaks can only occur when the map/array is indefinite length + if(!DecodeNesting_IsIndefiniteLength(pNesting)) { + return QCBOR_ERR_BAD_BREAK; + } + + // if all OK, the break reduces the level of nesting + pNesting->pCurrent--; + + return QCBOR_SUCCESS; +} + +// Called on every single item except breaks including the opening of a map/array +inline static void DecodeNesting_DecrementCount(QCBORDecodeNesting *pNesting) +{ + if(!DecodeNesting_IsNested(pNesting)) { + // at top level where there is no tracking + return; + } + + if(DecodeNesting_IsIndefiniteLength(pNesting)) { + // There is no count for indefinite length arrays/maps + return; + } + + // Decrement the count of items in this array/map + pNesting->pCurrent->uCount--; + + // Pop up nesting levels if the counts at the levels are zero + while(DecodeNesting_IsNested(pNesting) && 0 == pNesting->pCurrent->uCount) { + pNesting->pCurrent--; + if(!DecodeNesting_IsIndefiniteLength(pNesting)) { + pNesting->pCurrent->uCount--; + } + } +} + +// Called on every map/array +inline static QCBORError DecodeNesting_Descend(QCBORDecodeNesting *pNesting, QCBORItem *pItem) +{ + QCBORError nReturn = QCBOR_SUCCESS; + + if(pItem->val.uCount == 0) { + // Nothing to do for empty definite lenth arrays. They are just are + // effectively the same as an item that is not a map or array + goto Done; + // Empty indefinite length maps and arrays are handled elsewhere + } + + // Error out if arrays is too long to handle + if(pItem->val.uCount != UINT16_MAX && pItem->val.uCount > QCBOR_MAX_ITEMS_IN_ARRAY) { + nReturn = QCBOR_ERR_ARRAY_TOO_LONG; + goto Done; + } + + // Error out if nesting is too deep + if(pNesting->pCurrent >= &(pNesting->pMapsAndArrays[QCBOR_MAX_ARRAY_NESTING])) { + nReturn = QCBOR_ERR_ARRAY_NESTING_TOO_DEEP; + goto Done; + } + + // The actual descend + pNesting->pCurrent++; + + // Record a few details for this nesting level + pNesting->pCurrent->uMajorType = pItem->uDataType; + pNesting->pCurrent->uCount = pItem->val.uCount; + +Done: + return nReturn;; +} + +inline static void DecodeNesting_Init(QCBORDecodeNesting *pNesting) +{ + pNesting->pCurrent = &(pNesting->pMapsAndArrays[0]); +} + + + +/* + This list of built-in tags. Only add tags here that are + clearly established and useful. Once a tag is added here + it can't be taken out as that would break backwards compatibility. + There are only 48 slots available forever. + */ +static const uint16_t spBuiltInTagMap[] = { + CBOR_TAG_DATE_STRING, // See TAG_MAPPER_FIRST_FOUR + CBOR_TAG_DATE_EPOCH, // See TAG_MAPPER_FIRST_FOUR + CBOR_TAG_POS_BIGNUM, // See TAG_MAPPER_FIRST_FOUR + CBOR_TAG_NEG_BIGNUM, // See TAG_MAPPER_FIRST_FOUR + CBOR_TAG_FRACTION, + CBOR_TAG_BIGFLOAT, + CBOR_TAG_COSE_ENCRYPTO, + CBOR_TAG_COSE_MAC0, + CBOR_TAG_COSE_SIGN1, + CBOR_TAG_ENC_AS_B64URL, + CBOR_TAG_ENC_AS_B64, + CBOR_TAG_ENC_AS_B16, + CBOR_TAG_CBOR, + CBOR_TAG_URI, + CBOR_TAG_B64URL, + CBOR_TAG_B64, + CBOR_TAG_REGEX, + CBOR_TAG_MIME, + CBOR_TAG_BIN_UUID, + CBOR_TAG_CWT, + CBOR_TAG_ENCRYPT, + CBOR_TAG_MAC, + CBOR_TAG_SIGN, + CBOR_TAG_GEO_COORD, + CBOR_TAG_CBOR_MAGIC +}; + +// This is used in a bit of cleverness in GetNext_TaggedItem() to +// keep code size down and switch for the internal processing of +// these types. This will break if the first four items in +// spBuiltInTagMap don't have values 0,1,2,3. That is the +// mapping is 0 to 0, 1 to 1, 2 to 2 and 3 to 3. +#define QCBOR_TAGFLAG_DATE_STRING (0x01LL << CBOR_TAG_DATE_STRING) +#define QCBOR_TAGFLAG_DATE_EPOCH (0x01LL << CBOR_TAG_DATE_EPOCH) +#define QCBOR_TAGFLAG_POS_BIGNUM (0x01LL << CBOR_TAG_POS_BIGNUM) +#define QCBOR_TAGFLAG_NEG_BIGNUM (0x01LL << CBOR_TAG_NEG_BIGNUM) + +#define TAG_MAPPER_FIRST_FOUR (QCBOR_TAGFLAG_DATE_STRING |\ + QCBOR_TAGFLAG_DATE_EPOCH |\ + QCBOR_TAGFLAG_POS_BIGNUM |\ + QCBOR_TAGFLAG_NEG_BIGNUM) + +#define TAG_MAPPER_TOTAL_TAG_BITS 64 // Number of bits in a uint64_t +#define TAG_MAPPER_CUSTOM_TAGS_BASE_INDEX (TAG_MAPPER_TOTAL_TAG_BITS - QCBOR_MAX_CUSTOM_TAGS) // 48 +#define TAG_MAPPER_MAX_SIZE_BUILT_IN_TAGS (TAG_MAPPER_TOTAL_TAG_BITS - QCBOR_MAX_CUSTOM_TAGS ) // 48 + +static inline int TagMapper_LookupBuiltIn(uint64_t uTag) +{ + if(sizeof(spBuiltInTagMap)/sizeof(uint16_t) > TAG_MAPPER_MAX_SIZE_BUILT_IN_TAGS) { + // This is a cross-check to make sure the above array doesn't + // accidentally get made too big. + // In normal conditions the above test should optimize out + // as all the values are known at compile time. + return -1; + } + + if(uTag > UINT16_MAX) { + // This tag map works only on 16-bit tags + return -1; + } + + for(int nTagBitIndex = 0; nTagBitIndex < (int)(sizeof(spBuiltInTagMap)/sizeof(uint16_t)); nTagBitIndex++) { + if(spBuiltInTagMap[nTagBitIndex] == uTag) { + return nTagBitIndex; + } + } + return -1; // Indicates no match +} + +static inline int TagMapper_LookupCallerConfigured(const QCBORTagListIn *pCallerConfiguredTagMap, uint64_t uTag) +{ + for(int nTagBitIndex = 0; nTagBitIndex < pCallerConfiguredTagMap->uNumTags; nTagBitIndex++) { + if(pCallerConfiguredTagMap->puTags[nTagBitIndex] == uTag) { + return nTagBitIndex + TAG_MAPPER_CUSTOM_TAGS_BASE_INDEX; + } + } + + return -1; // Indicates no match +} + +/* + Find the tag bit index for a given tag value, or error out + + This and the above functions could probably be optimized and made + clearer and neater. + */ +static QCBORError TagMapper_Lookup(const QCBORTagListIn *pCallerConfiguredTagMap, uint64_t uTag, uint8_t *puTagBitIndex) +{ + int nTagBitIndex = TagMapper_LookupBuiltIn(uTag); + if(nTagBitIndex >= 0) { + // Cast is safe because TagMapper_LookupBuiltIn never returns > 47 + *puTagBitIndex = (uint8_t)nTagBitIndex; + return QCBOR_SUCCESS; + } + + if(pCallerConfiguredTagMap) { + if(pCallerConfiguredTagMap->uNumTags > QCBOR_MAX_CUSTOM_TAGS) { + return QCBOR_ERR_TOO_MANY_TAGS; + } + nTagBitIndex = TagMapper_LookupCallerConfigured(pCallerConfiguredTagMap, uTag); + if(nTagBitIndex >= 0) { + // Cast is safe because TagMapper_LookupBuiltIn never returns > 63 + + *puTagBitIndex = (uint8_t)nTagBitIndex; + return QCBOR_SUCCESS; + } + } + + return QCBOR_ERR_BAD_OPT_TAG; +} + + + + +/* + Public function, see header file + */ +void QCBORDecode_Init(QCBORDecodeContext *me, UsefulBufC EncodedCBOR, QCBORDecodeMode nDecodeMode) +{ + memset(me, 0, sizeof(QCBORDecodeContext)); + UsefulInputBuf_Init(&(me->InBuf), EncodedCBOR); + // Don't bother with error check on decode mode. If a bad value is passed it will just act as + // if the default normal mode of 0 was set. + me->uDecodeMode = nDecodeMode; + DecodeNesting_Init(&(me->nesting)); +} + + +/* + Public function, see header file + */ +void QCBORDecode_SetUpAllocator(QCBORDecodeContext *pCtx, const QCBORStringAllocator *pAllocator, bool bAllocAll) +{ + pCtx->pStringAllocator = (void *)pAllocator; + pCtx->bStringAllocateAll = bAllocAll; +} + +void QCBORDecode_SetCallerConfiguredTagList(QCBORDecodeContext *me, const QCBORTagListIn *pTagList) +{ + me->pCallerConfiguredTagList = pTagList; +} + + +/* + This decodes the fundamental part of a CBOR data item, the type and number + + This is the Counterpart to InsertEncodedTypeAndNumber(). + + This does the network->host byte order conversion. The conversion here + also results in the conversion for floats in addition to that for + lengths, tags and integer values. + + This returns: + pnMajorType -- the major type for the item + puNumber -- the "number" which is used a the value for integers, tags and floats and length for strings and arrays + puAdditionalInfo -- Pass this along to know what kind of float or if length is indefinite + + */ +inline static QCBORError DecodeTypeAndNumber(UsefulInputBuf *pUInBuf, + int *pnMajorType, + uint64_t *puArgument, + uint8_t *puAdditionalInfo) +{ + QCBORError nReturn; + + // Get the initial byte that every CBOR data item has + const uint8_t uInitialByte = UsefulInputBuf_GetByte(pUInBuf); + + // Break down the initial byte + const uint8_t uTmpMajorType = uInitialByte >> 5; + const uint8_t uAdditionalInfo = uInitialByte & 0x1f; + + // Where the number or argument accumulates + uint64_t uArgument; + + if(uAdditionalInfo >= LEN_IS_ONE_BYTE && uAdditionalInfo <= LEN_IS_EIGHT_BYTES) { + // Need to get 1,2,4 or 8 additional argument bytes + // Map LEN_IS_ONE_BYTE.. LEN_IS_EIGHT_BYTES to actual length + static const uint8_t aIterate[] = {1,2,4,8}; + + // Loop getting all the bytes in the argument + uArgument = 0; + for(int i = aIterate[uAdditionalInfo - LEN_IS_ONE_BYTE]; i; i--) { + // This shift and add gives the endian conversion + uArgument = (uArgument << 8) + UsefulInputBuf_GetByte(pUInBuf); + } + } else if(uAdditionalInfo >= ADDINFO_RESERVED1 && uAdditionalInfo <= ADDINFO_RESERVED3) { + // The reserved and thus-far unused additional info values + nReturn = QCBOR_ERR_UNSUPPORTED; + goto Done; + } else { + // Less than 24, additional info is argument or 31, an indefinite length + // No more bytes to get + uArgument = uAdditionalInfo; + } + + if(UsefulInputBuf_GetError(pUInBuf)) { + nReturn = QCBOR_ERR_HIT_END; + goto Done; + } + + // All successful if we got here. + nReturn = QCBOR_SUCCESS; + *pnMajorType = uTmpMajorType; + *puArgument = uArgument; + *puAdditionalInfo = uAdditionalInfo; + +Done: + return nReturn; +} + +/* + CBOR doesn't explicitly specify two's compliment for integers but all CPUs + use it these days and the test vectors in the RFC are so. All integers in the CBOR + structure are positive and the major type indicates positive or negative. + CBOR can express positive integers up to 2^x - 1 where x is the number of bits + and negative integers down to 2^x. Note that negative numbers can be one + more away from zero than positive. + Stdint, as far as I can tell, uses two's compliment to represent + negative integers. + + See http://www.unix.org/whitepapers/64bit.html for reasons int isn't + used here in any way including in the interface + */ +inline static QCBORError DecodeInteger(int nMajorType, uint64_t uNumber, QCBORItem *pDecodedItem) +{ + // Stack usage: int/ptr 1 -- 8 + QCBORError nReturn = QCBOR_SUCCESS; + + if(nMajorType == CBOR_MAJOR_TYPE_POSITIVE_INT) { + if (uNumber <= INT64_MAX) { + pDecodedItem->val.int64 = (int64_t)uNumber; + pDecodedItem->uDataType = QCBOR_TYPE_INT64; + + } else { + pDecodedItem->val.uint64 = uNumber; + pDecodedItem->uDataType = QCBOR_TYPE_UINT64; + + } + } else { + if(uNumber <= INT64_MAX) { + pDecodedItem->val.int64 = -uNumber-1; + pDecodedItem->uDataType = QCBOR_TYPE_INT64; + + } else { + // C can't represent a negative integer in this range + // so it is an error. todo -- test this condition + nReturn = QCBOR_ERR_INT_OVERFLOW; + } + } + + return nReturn; +} + +// Make sure #define value line up as DecodeSimple counts on this. +#if QCBOR_TYPE_FALSE != CBOR_SIMPLEV_FALSE +#error QCBOR_TYPE_FALSE macro value wrong +#endif + +#if QCBOR_TYPE_TRUE != CBOR_SIMPLEV_TRUE +#error QCBOR_TYPE_TRUE macro value wrong +#endif + +#if QCBOR_TYPE_NULL != CBOR_SIMPLEV_NULL +#error QCBOR_TYPE_NULL macro value wrong +#endif + +#if QCBOR_TYPE_UNDEF != CBOR_SIMPLEV_UNDEF +#error QCBOR_TYPE_UNDEF macro value wrong +#endif + +#if QCBOR_TYPE_BREAK != CBOR_SIMPLE_BREAK +#error QCBOR_TYPE_BREAK macro value wrong +#endif + +#if QCBOR_TYPE_DOUBLE != DOUBLE_PREC_FLOAT +#error QCBOR_TYPE_DOUBLE macro value wrong +#endif + +#if QCBOR_TYPE_FLOAT != SINGLE_PREC_FLOAT +#error QCBOR_TYPE_FLOAT macro value wrong +#endif + +/* + Decode true, false, floats, break... + */ + +inline static QCBORError DecodeSimple(uint8_t uAdditionalInfo, uint64_t uNumber, QCBORItem *pDecodedItem) +{ + // Stack usage: 0 + QCBORError nReturn = QCBOR_SUCCESS; + + // uAdditionalInfo is 5 bits from the initial byte + // compile time checks above make sure uAdditionalInfo values line up with uDataType values + pDecodedItem->uDataType = uAdditionalInfo; + + switch(uAdditionalInfo) { + case ADDINFO_RESERVED1: // 28 + case ADDINFO_RESERVED2: // 29 + case ADDINFO_RESERVED3: // 30 + nReturn = QCBOR_ERR_UNSUPPORTED; + break; + + case HALF_PREC_FLOAT: + pDecodedItem->val.dfnum = IEEE754_HalfToDouble((uint16_t)uNumber); + pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE; + break; + case SINGLE_PREC_FLOAT: + pDecodedItem->val.dfnum = (double)UsefulBufUtil_CopyUint32ToFloat((uint32_t)uNumber); + pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE; + break; + case DOUBLE_PREC_FLOAT: + pDecodedItem->val.dfnum = UsefulBufUtil_CopyUint64ToDouble(uNumber); + pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE; + break; + + case CBOR_SIMPLEV_FALSE: // 20 + case CBOR_SIMPLEV_TRUE: // 21 + case CBOR_SIMPLEV_NULL: // 22 + case CBOR_SIMPLEV_UNDEF: // 23 + case CBOR_SIMPLE_BREAK: // 31 + break; // nothing to do + + case CBOR_SIMPLEV_ONEBYTE: // 24 + if(uNumber <= CBOR_SIMPLE_BREAK) { + // This takes out f8 00 ... f8 1f which should be encoded as e0 … f7 + nReturn = QCBOR_ERR_INVALID_CBOR; + goto Done; + } + /* FALLTHROUGH */ + // fall through intentionally + + default: // 0-19 + pDecodedItem->uDataType = QCBOR_TYPE_UKNOWN_SIMPLE; + // DecodeTypeAndNumber will make uNumber equal to uAdditionalInfo when uAdditionalInfo is < 24 + // This cast is safe because the 2, 4 and 8 byte lengths of uNumber are in the double/float cases above + pDecodedItem->val.uSimple = (uint8_t)uNumber; + break; + } + +Done: + return nReturn; +} + + + +/* + Decode text and byte strings. Call the string allocator if asked to. + */ +inline static QCBORError DecodeBytes(const QCBORStringAllocator *pAlloc, int nMajorType, uint64_t uStrLen, UsefulInputBuf *pUInBuf, QCBORItem *pDecodedItem) +{ + // Stack usage: UsefulBuf 2, int/ptr 1 40 + QCBORError nReturn = QCBOR_SUCCESS; + + const UsefulBufC Bytes = UsefulInputBuf_GetUsefulBuf(pUInBuf, uStrLen); + if(UsefulBuf_IsNULLC(Bytes)) { + // Failed to get the bytes for this string item + nReturn = QCBOR_ERR_HIT_END; + goto Done; + } + + if(pAlloc) { + // We are asked to use string allocator to make a copy + UsefulBuf NewMem = pAlloc->fAllocate(pAlloc->pAllocaterContext, NULL, uStrLen); + if(UsefulBuf_IsNULL(NewMem)) { + nReturn = QCBOR_ERR_STRING_ALLOCATE; + goto Done; + } + pDecodedItem->val.string = UsefulBuf_Copy(NewMem, Bytes); + } else { + // Normal case with no string allocator + pDecodedItem->val.string = Bytes; + } + pDecodedItem->uDataType = (nMajorType == CBOR_MAJOR_TYPE_BYTE_STRING) ? QCBOR_TYPE_BYTE_STRING : QCBOR_TYPE_TEXT_STRING; + +Done: + return nReturn; +} + + +/* + Mostly just assign the right data type for the date string. + */ +inline static QCBORError DecodeDateString(QCBORItem *pDecodedItem) +{ + // Stack Use: UsefulBuf 1 16 + if(pDecodedItem->uDataType != QCBOR_TYPE_TEXT_STRING) { + return QCBOR_ERR_BAD_OPT_TAG; + } + + const UsefulBufC Temp = pDecodedItem->val.string; + pDecodedItem->val.dateString = Temp; + pDecodedItem->uDataType = QCBOR_TYPE_DATE_STRING; + return QCBOR_SUCCESS; +} + + +/* + Mostly just assign the right data type for the bignum. + */ +inline static QCBORError DecodeBigNum(QCBORItem *pDecodedItem) +{ + // Stack Use: UsefulBuf 1 -- 16 + if(pDecodedItem->uDataType != QCBOR_TYPE_BYTE_STRING) { + return QCBOR_ERR_BAD_OPT_TAG; + } + const UsefulBufC Temp = pDecodedItem->val.string; + pDecodedItem->val.bigNum = Temp; + pDecodedItem->uDataType = pDecodedItem->uTagBits & QCBOR_TAGFLAG_POS_BIGNUM ? QCBOR_TYPE_POSBIGNUM : QCBOR_TYPE_NEGBIGNUM; + return QCBOR_SUCCESS; +} + + +/* + The epoch formatted date. Turns lots of different forms of encoding date into uniform one + */ +static int DecodeDateEpoch(QCBORItem *pDecodedItem) +{ + // Stack usage: 1 + QCBORError nReturn = QCBOR_SUCCESS; + + pDecodedItem->val.epochDate.fSecondsFraction = 0; + + switch (pDecodedItem->uDataType) { + + case QCBOR_TYPE_INT64: + pDecodedItem->val.epochDate.nSeconds = pDecodedItem->val.int64; + break; + + case QCBOR_TYPE_UINT64: + if(pDecodedItem->val.uint64 > INT64_MAX) { + nReturn = QCBOR_ERR_DATE_OVERFLOW; + goto Done; + } + pDecodedItem->val.epochDate.nSeconds = pDecodedItem->val.uint64; + break; + + case QCBOR_TYPE_DOUBLE: + { + const double d = pDecodedItem->val.dfnum; + if(d > INT64_MAX) { + nReturn = QCBOR_ERR_DATE_OVERFLOW; + goto Done; + } + pDecodedItem->val.epochDate.nSeconds = d; // Float to integer conversion happening here. + pDecodedItem->val.epochDate.fSecondsFraction = d - pDecodedItem->val.epochDate.nSeconds; + } + break; + + default: + nReturn = QCBOR_ERR_BAD_OPT_TAG; + goto Done; + } + pDecodedItem->uDataType = QCBOR_TYPE_DATE_EPOCH; + +Done: + return nReturn; +} + + + + +// Make sure the constants align as this is assumed by the GetAnItem() implementation +#if QCBOR_TYPE_ARRAY != CBOR_MAJOR_TYPE_ARRAY +#error QCBOR_TYPE_ARRAY value not lined up with major type +#endif +#if QCBOR_TYPE_MAP != CBOR_MAJOR_TYPE_MAP +#error QCBOR_TYPE_MAP value not lined up with major type +#endif + +/* + This gets a single data item and decodes it including preceding optional tagging. This does not + deal with arrays and maps and nesting except to decode the data item introducing them. Arrays and + maps are handled at the next level up in GetNext(). + + Errors detected here include: an array that is too long to decode, hit end of buffer unexpectedly, + a few forms of invalid encoded CBOR + */ +static QCBORError GetNext_Item(UsefulInputBuf *pUInBuf, QCBORItem *pDecodedItem, const QCBORStringAllocator *pAlloc) +{ + // Stack usage: int/ptr 3 -- 24 + QCBORError nReturn; + + // Get the major type and the number. Number could be length of more bytes or the value depending on the major type + // nAdditionalInfo is an encoding of the length of the uNumber and is needed to decode floats and doubles + int uMajorType; + uint64_t uNumber; + uint8_t uAdditionalInfo; + + nReturn = DecodeTypeAndNumber(pUInBuf, &uMajorType, &uNumber, &uAdditionalInfo); + + // Error out here if we got into trouble on the type and number. + // The code after this will not work if the type and number is not good. + if(nReturn) + goto Done; + + memset(pDecodedItem, 0, sizeof(QCBORItem)); + + // At this point the major type and the value are valid. We've got the type and the number that + // starts every CBOR data item. + switch (uMajorType) { + case CBOR_MAJOR_TYPE_POSITIVE_INT: // Major type 0 + case CBOR_MAJOR_TYPE_NEGATIVE_INT: // Major type 1 + nReturn = DecodeInteger(uMajorType, uNumber, pDecodedItem); + break; + + case CBOR_MAJOR_TYPE_BYTE_STRING: // Major type 2 + case CBOR_MAJOR_TYPE_TEXT_STRING: // Major type 3 + if(uAdditionalInfo == LEN_IS_INDEFINITE) { + pDecodedItem->uDataType = (uMajorType == CBOR_MAJOR_TYPE_BYTE_STRING) ? QCBOR_TYPE_BYTE_STRING : QCBOR_TYPE_TEXT_STRING; + pDecodedItem->val.string = (UsefulBufC){NULL, SIZE_MAX}; + } else { + nReturn = DecodeBytes(pAlloc, uMajorType, uNumber, pUInBuf, pDecodedItem); + } + break; + + case CBOR_MAJOR_TYPE_ARRAY: // Major type 4 + case CBOR_MAJOR_TYPE_MAP: // Major type 5 + // Record the number of items in the array or map + if(uNumber > QCBOR_MAX_ITEMS_IN_ARRAY) { + nReturn = QCBOR_ERR_ARRAY_TOO_LONG; + goto Done; + } + if(uAdditionalInfo == LEN_IS_INDEFINITE) { + pDecodedItem->val.uCount = UINT16_MAX; // Indicate indefinite length + } else { + pDecodedItem->val.uCount = (uint16_t)uNumber; // type conversion OK because of check above + } + pDecodedItem->uDataType = uMajorType; // C preproc #if above makes sure constants align + break; + + case CBOR_MAJOR_TYPE_OPTIONAL: // Major type 6, optional prepended tags + pDecodedItem->val.uTagV = uNumber; + pDecodedItem->uDataType = QCBOR_TYPE_OPTTAG; + break; + + case CBOR_MAJOR_TYPE_SIMPLE: // Major type 7, float, double, true, false, null... + nReturn = DecodeSimple(uAdditionalInfo, uNumber, pDecodedItem); + break; + + default: // Should never happen because DecodeTypeAndNumber() should never return > 7 + nReturn = QCBOR_ERR_UNSUPPORTED; + break; + } + +Done: + return nReturn; +} + + + +/* + This layer deals with indefinite length strings. It pulls all the + individual chunk items together into one QCBORItem using the + string allocator. + + Code Reviewers: THIS FUNCTION DOES A LITTLE POINTER MATH + */ +static inline QCBORError GetNext_FullItem(QCBORDecodeContext *me, QCBORItem *pDecodedItem) +{ + // Stack usage; int/ptr 2 UsefulBuf 2 QCBORItem -- 96 + QCBORError nReturn; + QCBORStringAllocator *pAlloc = (QCBORStringAllocator *)me->pStringAllocator; + UsefulBufC FullString = NULLUsefulBufC; + + nReturn = GetNext_Item(&(me->InBuf), pDecodedItem, me->bStringAllocateAll ? pAlloc: NULL); + if(nReturn) { + goto Done; + } + + // To reduce code size by removing support for indefinite length strings, the + // code in this function from here down can be eliminated. Run tests, except + // indefinite length string tests, to be sure all is OK if this is removed. + + // Only do indefinite length processing on strings + if(pDecodedItem->uDataType != QCBOR_TYPE_BYTE_STRING && pDecodedItem->uDataType != QCBOR_TYPE_TEXT_STRING) { + goto Done; // no need to do any work here on non-string types + } + + // Is this a string with an indefinite length? + if(pDecodedItem->val.string.len != SIZE_MAX) { + goto Done; // length is not indefinite, so no work to do here + } + + // Can't do indefinite length strings without a string allocator + if(pAlloc == NULL) { + nReturn = QCBOR_ERR_NO_STRING_ALLOCATOR; + goto Done; + } + + // There is an indefinite length string to work on... + // Track which type of string it is + const uint8_t uStringType = pDecodedItem->uDataType; + + // Loop getting chunk of indefinite string + for(;;) { + // Get item for next chunk + QCBORItem StringChunkItem; + // NULL passed to never string alloc chunk of indefinite length strings + nReturn = GetNext_Item(&(me->InBuf), &StringChunkItem, NULL); + if(nReturn) { + break; // Error getting the next chunk + } + + // See if it is a marker at end of indefinite length string + if(StringChunkItem.uDataType == QCBOR_TYPE_BREAK) { + // String is complete + pDecodedItem->val.string = FullString; + pDecodedItem->uDataAlloc = 1; + break; + } + + // Match data type of chunk to type at beginning. + // Also catches error of other non-string types that don't belong. + if(StringChunkItem.uDataType != uStringType) { + nReturn = QCBOR_ERR_INDEFINITE_STRING_CHUNK; + break; + } + + // Alloc new buffer or expand previously allocated buffer so it can fit + UsefulBuf NewMem = (*pAlloc->fAllocate)(pAlloc->pAllocaterContext, + UNCONST_POINTER(FullString.ptr), + FullString.len + StringChunkItem.val.string.len); + if(UsefulBuf_IsNULL(NewMem)) { + // Allocation of memory for the string failed + nReturn = QCBOR_ERR_STRING_ALLOCATE; + break; + } + + // Copy new string chunk at the end of string so far. + FullString = UsefulBuf_CopyOffset(NewMem, FullString.len, StringChunkItem.val.string); + } + +Done: + if(pAlloc && nReturn && !UsefulBuf_IsNULLC(FullString)) { + // Getting item failed, clean up the allocated memory + (pAlloc->fFree)(pAlloc->pAllocaterContext, UNCONST_POINTER(FullString.ptr)); + } + + return nReturn; +} + + +/* + Returns an error if there was something wrong with the optional item or it couldn't + be handled. + */ +static QCBORError GetNext_TaggedItem(QCBORDecodeContext *me, QCBORItem *pDecodedItem, QCBORTagListOut *pTags) +{ + // Stack usage: int/ptr: 3 -- 24 + QCBORError nReturn; + uint64_t uTagBits = 0; + if(pTags) { + pTags->uNumUsed = 0; + } + + for(;;) { + nReturn = GetNext_FullItem(me, pDecodedItem); + if(nReturn) { + goto Done; // Error out of the loop + } + + if(pDecodedItem->uDataType != QCBOR_TYPE_OPTTAG) { + // Successful exit from loop; maybe got some tags, maybe not + pDecodedItem->uTagBits = uTagBits; + break; + } + + uint8_t uTagBitIndex; + // Tag was mapped, tag was not mapped, error with tag list + switch(TagMapper_Lookup(me->pCallerConfiguredTagList, pDecodedItem->val.uTagV, &uTagBitIndex)) { + + case QCBOR_SUCCESS: + // Successfully mapped the tag + uTagBits |= 0x01ULL << uTagBitIndex; + break; + + case QCBOR_ERR_BAD_OPT_TAG: + // Tag is not recognized. Do nothing + break; + + default: + // Error Condition + goto Done; + } + + if(pTags) { + // Caller wants all tags recorded in the provided buffer + if(pTags->uNumUsed >= pTags->uNumAllocated) { + nReturn = QCBOR_ERR_TOO_MANY_TAGS; + goto Done; + } + pTags->puTags[pTags->uNumUsed] = pDecodedItem->val.uTagV; + pTags->uNumUsed++; + } + } + + switch(pDecodedItem->uTagBits & TAG_MAPPER_FIRST_FOUR) { + case 0: + // No tags at all or none we know about. Nothing to do. + // This is part of the pass-through path of this function + // that will mostly be taken when decoding any item. + break; + + case QCBOR_TAGFLAG_DATE_STRING: + nReturn = DecodeDateString(pDecodedItem); + break; + + case QCBOR_TAGFLAG_DATE_EPOCH: + nReturn = DecodeDateEpoch(pDecodedItem); + break; + + case QCBOR_TAGFLAG_POS_BIGNUM: + case QCBOR_TAGFLAG_NEG_BIGNUM: + nReturn = DecodeBigNum(pDecodedItem); + break; + + default: + // Encountering some mixed up CBOR like something that + // is tagged as both a string and integer date. + nReturn = QCBOR_ERR_BAD_OPT_TAG; + } + +Done: + return nReturn; +} + + +/* + This layer takes care of map entries. It combines the label and data items into one QCBORItem. + */ +static inline QCBORError GetNext_MapEntry(QCBORDecodeContext *me, QCBORItem *pDecodedItem, QCBORTagListOut *pTags) +{ + // Stack use: int/ptr 1, QCBORItem -- 56 + QCBORError nReturn = GetNext_TaggedItem(me, pDecodedItem, pTags); + if(nReturn) + goto Done; + + if(pDecodedItem->uDataType == QCBOR_TYPE_BREAK) { + // Break can't be a map entry + goto Done; + } + + if(me->uDecodeMode != QCBOR_DECODE_MODE_MAP_AS_ARRAY) { + // In a map and caller wants maps decoded, not treated as arrays + + if(DecodeNesting_TypeIsMap(&(me->nesting))) { + // If in a map and the right decoding mode, get the label + + // Get the next item which will be the real data; Item will be the label + QCBORItem LabelItem = *pDecodedItem; + nReturn = GetNext_TaggedItem(me, pDecodedItem, pTags); + if(nReturn) + goto Done; + + pDecodedItem->uLabelAlloc = LabelItem.uDataAlloc; + + if(LabelItem.uDataType == QCBOR_TYPE_TEXT_STRING) { + // strings are always good labels + pDecodedItem->label.string = LabelItem.val.string; + pDecodedItem->uLabelType = QCBOR_TYPE_TEXT_STRING; + } else if (QCBOR_DECODE_MODE_MAP_STRINGS_ONLY == me->uDecodeMode) { + // It's not a string and we only want strings, probably for easy translation to JSON + nReturn = QCBOR_ERR_MAP_LABEL_TYPE; + goto Done; + } else if(LabelItem.uDataType == QCBOR_TYPE_INT64) { + pDecodedItem->label.int64 = LabelItem.val.int64; + pDecodedItem->uLabelType = QCBOR_TYPE_INT64; + } else if(LabelItem.uDataType == QCBOR_TYPE_UINT64) { + pDecodedItem->label.uint64 = LabelItem.val.uint64; + pDecodedItem->uLabelType = QCBOR_TYPE_UINT64; + } else if(LabelItem.uDataType == QCBOR_TYPE_BYTE_STRING) { + pDecodedItem->label.string = LabelItem.val.string; + pDecodedItem->uLabelAlloc = LabelItem.uDataAlloc; + pDecodedItem->uLabelType = QCBOR_TYPE_BYTE_STRING; + } else { + // label is not an int or a string. It is an arrray + // or a float or such and this implementation doesn't handle that. + // Also, tags on labels are ignored. + nReturn = QCBOR_ERR_MAP_LABEL_TYPE; + goto Done; + } + } + } else { + if(pDecodedItem->uDataType == QCBOR_TYPE_MAP) { + // Decoding a map as an array + pDecodedItem->uDataType = QCBOR_TYPE_MAP_AS_ARRAY; + pDecodedItem->val.uCount *= 2; + } + } + +Done: + return nReturn; +} + + +/* + Public function, see header qcbor.h file + */ +QCBORError QCBORDecode_GetNextWithTags(QCBORDecodeContext *me, QCBORItem *pDecodedItem, QCBORTagListOut *pTags) +{ + // Stack ptr/int: 2, QCBORItem : 64 + + // The public entry point for fetching and parsing the next QCBORItem. + // All the CBOR parsing work is here and in subordinate calls. + QCBORError nReturn; + + nReturn = GetNext_MapEntry(me, pDecodedItem, pTags); + if(nReturn) { + goto Done; + } + + // Break ending arrays/maps are always processed at the end of this function. + // They should never show up here. + if(pDecodedItem->uDataType == QCBOR_TYPE_BREAK) { + nReturn = QCBOR_ERR_BAD_BREAK; + goto Done; + } + + // Record the nesting level for this data item before processing any of + // decrementing and descending. + pDecodedItem->uNestingLevel = DecodeNesting_GetLevel(&(me->nesting)); + + // Process the item just received for descent or decrement, and + // ascent if decrements are enough to close out a definite length array/map + if(IsMapOrArray(pDecodedItem->uDataType)) { + // If the new item is array or map, the nesting level descends + nReturn = DecodeNesting_Descend(&(me->nesting), pDecodedItem); + // Maps and arrays do count in as items in the map/array that encloses + // them so a decrement needs to be done for them too, but that is done + // only when all the items in them have been processed, not when they + // are opened. + } else { + // Decrement the count of items in the enclosing map/array + // If the count in the enclosing map/array goes to zero, that + // triggers a decrement in the map/array above that and + // an ascend in nesting level. + DecodeNesting_DecrementCount(&(me->nesting)); + } + if(nReturn) { + goto Done; + } + + // For indefinite length maps/arrays, looking at any and + // all breaks that might terminate them. The equivalent + // for definite length maps/arrays happens in + // DecodeNesting_DecrementCount(). + if(DecodeNesting_IsNested(&(me->nesting)) && DecodeNesting_IsIndefiniteLength(&(me->nesting))) { + while(UsefulInputBuf_BytesUnconsumed(&(me->InBuf))) { + // Peek forward one item to see if it is a break. + QCBORItem Peek; + size_t uPeek = UsefulInputBuf_Tell(&(me->InBuf)); + nReturn = GetNext_Item(&(me->InBuf), &Peek, NULL); + if(nReturn) { + goto Done; + } + if(Peek.uDataType != QCBOR_TYPE_BREAK) { + // It is not a break, rewind so it can be processed normally. + UsefulInputBuf_Seek(&(me->InBuf), uPeek); + break; + } + // It is a break. Ascend one nesting level. + // The break is consumed. + nReturn = DecodeNesting_BreakAscend(&(me->nesting)); + if(nReturn) { + // break occured outside of an indefinite length array/map + goto Done; + } + } + } + + // Tell the caller what level is next. This tells them what maps/arrays + // were closed out and makes it possible for them to reconstruct + // the tree with just the information returned by GetNext + pDecodedItem->uNextNestLevel = DecodeNesting_GetLevel(&(me->nesting)); + +Done: + return nReturn; +} + + +QCBORError QCBORDecode_GetNext(QCBORDecodeContext *me, QCBORItem *pDecodedItem) +{ + return QCBORDecode_GetNextWithTags(me, pDecodedItem, NULL); +} + + +/* + Decoding items is done in 5 layered functions, one calling the + next one down. If a layer has no work to do for a particular item + it returns quickly. + + - QCBORDecode_GetNext -- The top layer manages the beginnings and + ends of maps and arrays. It tracks descending into and ascending + out of maps/arrays. It processes all breaks that terminate + maps and arrays. + + - GetNext_MapEntry -- This handles the combining of two + items, the label and the data, that make up a map entry. + It only does work on maps. It combines the label and data + items into one labeled item. + + - GetNext_TaggedItem -- This handles the type 6 tagged items. + It accumulates all the tags and combines them with the following + non-tagged item. If the tagged item is something that is understood + like a date, the decoding of that item is invoked. + + - GetNext_FullItem -- This assembles the sub items that make up + an indefinte length string into one string item. It uses the + string allocater to create contiguous space for the item. It + processes all breaks that are part of indefinite length strings. + + - GetNext_Item -- This gets and decodes the most atomic + item in CBOR, the thing with an initial byte containing + the major type. + + Roughly this takes 300 bytes of stack for vars. Need to + evaluate this more carefully and correctly. + + */ + + +/* + Public function, see header qcbor.h file + */ +int QCBORDecode_IsTagged(QCBORDecodeContext *me, const QCBORItem *pItem, uint64_t uTag) +{ + const QCBORTagListIn *pCallerConfiguredTagMap = me->pCallerConfiguredTagList; + + uint8_t uTagBitIndex; + // Do not care about errors in pCallerConfiguredTagMap here. They are + // caught during GetNext() before this is called. + if(TagMapper_Lookup(pCallerConfiguredTagMap, uTag, &uTagBitIndex)) { + return 0; + } + + const uint64_t uTagBit = 0x01ULL << uTagBitIndex; + return (uTagBit & pItem->uTagBits) != 0; +} + + +/* + Public function, see header qcbor.h file + */ +QCBORError QCBORDecode_Finish(QCBORDecodeContext *me) +{ + int nReturn = QCBOR_SUCCESS; + + // Error out if all the maps/arrays are not closed out + if(DecodeNesting_IsNested(&(me->nesting))) { + nReturn = QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN; + goto Done; + } + + // Error out if not all the bytes are consumed + if(UsefulInputBuf_BytesUnconsumed(&(me->InBuf))) { + nReturn = QCBOR_ERR_EXTRA_BYTES; + } + +Done: + // Call the destructor for the string allocator if there is one. + // Always called, even if there are errors; always have to clean up + if(me->pStringAllocator) { + QCBORStringAllocator *pAllocator = (QCBORStringAllocator *)me->pStringAllocator; + if(pAllocator->fDestructor) { + (pAllocator->fDestructor)(pAllocator->pAllocaterContext); + } + } + + return nReturn; +} + + + +/* + +Decoder errors handled in this file + + - Hit end of input before it was expected while decoding type and number QCBOR_ERR_HIT_END + + - negative integer that is too large for C QCBOR_ERR_INT_OVERFLOW + + - Hit end of input while decoding a text or byte string QCBOR_ERR_HIT_END + + - Encountered conflicting tags -- e.g., an item is tagged both a date string and an epoch date QCBOR_ERR_UNSUPPORTED + + - Encontered an array or mapp that has too many items QCBOR_ERR_ARRAY_TOO_LONG + + - Encountered array/map nesting that is too deep QCBOR_ERR_ARRAY_NESTING_TOO_DEEP + + - An epoch date > INT64_MAX or < INT64_MIN was encountered QCBOR_ERR_DATE_OVERFLOW + + - The type of a map label is not a string or int QCBOR_ERR_MAP_LABEL_TYPE + + - Hit end with arrays or maps still open -- QCBOR_ERR_EXTRA_BYTES + + */ + + + + +/* + This is a very primitive memory allocator. It does not track individual + allocations, only a high-water mark. A free or reallotcation must be of + the last chunk allocated. + + All of this following code will get dead-stripped if QCBORDecode_SetMemPool() + is not called. + */ + +typedef struct { + QCBORStringAllocator StringAllocator; + uint8_t *pStart; // First byte that can be allocated + uint8_t *pEnd; // One past the last byte that can be allocated + uint8_t *pFree; // Where the next free chunk is +} MemPool; + + +/* + Internal function for an allocation + + Code Reviewers: THIS FUNCTION DOES POINTER MATH + */ +static UsefulBuf MemPool_Alloc(void *ctx, void *pMem, size_t uNewSize) +{ + MemPool *me = (MemPool *)ctx; + void *pReturn = NULL; + + if(pMem) { + // Realloc case + // This check will work even if uNewSize is a super-large value like UINT64_MAX + if((uNewSize <= (size_t)(me->pEnd - (uint8_t *)pMem)) && ((uint8_t *)pMem >= me->pStart)) { + me->pFree = (uint8_t *)pMem + uNewSize; + pReturn = pMem; + } + } else { + // New chunk case + // This check will work even if uNewSize is a super large value like UINT64_MAX + if(uNewSize <= (size_t)(me->pEnd - me->pFree)) { + pReturn = me->pFree; + me->pFree += uNewSize; + } + } + + return (UsefulBuf){pReturn, uNewSize}; +} + +/* + Internal function to free memory + */ +static void MemPool_Free(void *ctx, void *pOldMem) +{ + MemPool *me = (MemPool *)ctx; + me->pFree = pOldMem; +} + +/* + Public function, see header qcbor.h file + */ +QCBORError QCBORDecode_SetMemPool(QCBORDecodeContext *me, UsefulBuf Pool, bool bAllStrings) +{ + // The idea behind QCBOR_MIN_MEM_POOL_SIZE is + // that the caller knows exactly what size to + // allocate and that the tests can run conclusively + // no matter what size MemPool is + // even though it wastes some memory. MemPool + // will vary depending on pointer size of the + // the machine. QCBOR_MIN_MEM_POOL_SIZE is + // set for pointers up to 64-bits. This + // wastes about 50 bytes on a 32-bit machine. + // This check makes sure things don't go + // horribly wrong. It should optimize out + // when there is no problem as the sizes are + // known at compile time. + if(sizeof(MemPool) > QCBOR_DECODE_MIN_MEM_POOL_SIZE) { + return QCBOR_ERR_MEM_POOL_INTERNAL; + } + + // The first bytes of the Pool passed in are used + // as the context (vtable of sorts) for the memory pool + // allocator. + if(Pool.len < QCBOR_DECODE_MIN_MEM_POOL_SIZE) { + return QCBOR_ERR_BUFFER_TOO_SMALL; + } + MemPool *pMP = (MemPool *)Pool.ptr; + + // Fill in the "vtable" + pMP->StringAllocator.fAllocate = MemPool_Alloc; + pMP->StringAllocator.fFree = MemPool_Free; + pMP->StringAllocator.fDestructor = NULL; + + // Set up the pointers to the memory to be allocated + pMP->pStart = (uint8_t *)Pool.ptr + QCBOR_DECODE_MIN_MEM_POOL_SIZE; + pMP->pFree = pMP->pStart; + pMP->pEnd = (uint8_t *)Pool.ptr + Pool.len; + + // More book keeping of context + pMP->StringAllocator.pAllocaterContext = pMP; + me->pStringAllocator = pMP; + + // The flag indicating when to use the allocator + me->bStringAllocateAll = bAllStrings; + + return QCBOR_SUCCESS; +} + + +/* + Extra little hook to make MemPool testing work right + without adding any code size or overhead to non-test + uses. This will get dead-stripped for non-test use. + + This is not a public function. + */ +size_t MemPoolTestHook_GetPoolSize(void *ctx) +{ + MemPool *me = (MemPool *)ctx; + + return me->pEnd - me->pStart; +} + diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/qcbor/src/qcbor_encode.c b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/qcbor/src/qcbor_encode.c new file mode 100644 index 0000000..d18d811 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/qcbor/src/qcbor_encode.c @@ -0,0 +1,651 @@ +/*============================================================================== + Copyright (c) 2016-2018, The Linux Foundation. + Copyright (c) 2018-2019, Laurence Lundblade. + All rights reserved. + SPDX-License-Identifier: BSD-3-Clause + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of The Linux Foundation nor the names of its + contributors, nor the name "Laurence Lundblade" may be used to + endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ==============================================================================*/ + +/*=================================================================================== + FILE: qcbor_encode.c + + DESCRIPTION: This file contains the implementation of QCBOR. + + EDIT HISTORY FOR FILE: + + This section contains comments describing changes made to the module. + Notice that changes are listed in reverse chronological order. + + when who what, where, why + -------- ---- --------------------------------------------------- + 12/30/18 llundblade Small efficient clever encode of type & argument. + 11/29/18 llundblade Rework to simpler handling of tags and labels. + 11/9/18 llundblade Error codes are now enums. + 11/1/18 llundblade Floating support. + 10/31/18 llundblade Switch to one license that is almost BSD-3. + 09/28/18 llundblade Added bstr wrapping feature for COSE implementation. + 02/05/18 llundbla Works on CPUs which require integer alignment. + Requires new version of UsefulBuf. + 07/05/17 llundbla Add bstr wrapping of maps/arrays for COSE + 03/01/17 llundbla More data types + 11/13/16 llundbla Integrate most TZ changes back into github version. + 09/30/16 gkanike Porting to TZ. + 03/15/16 llundbla Initial Version. + + =====================================================================================*/ + +#include "qcbor.h" +#include "ieee754.h" + + +/*...... This is a ruler that is 80 characters long...........................*/ + + +/* + CBOR's two nesting types, arrays and maps, are tracked here. There is a + limit of QCBOR_MAX_ARRAY_NESTING to the number of arrays and maps + that can be nested in one encoding so the encoding context stays + small enough to fit on the stack. + + When an array / map is opened, pCurrentNesting points to the element + in pArrays that records the type, start position and accumluates a + count of the number of items added. When closed the start position is + used to go back and fill in the type and number of items in the array + / map. + + Encoded output be just items like ints and strings that are + not part of any array / map. That is, the first thing encoded + does not have to be an array or a map. + */ +inline static void Nesting_Init(QCBORTrackNesting *pNesting) +{ + // assumes pNesting has been zeroed + pNesting->pCurrentNesting = &pNesting->pArrays[0]; + // Implied CBOR array at the top nesting level. This is never returned, + // but makes the item count work correctly. + pNesting->pCurrentNesting->uMajorType = CBOR_MAJOR_TYPE_ARRAY; +} + +inline static QCBORError Nesting_Increase(QCBORTrackNesting *pNesting, + uint8_t uMajorType, + uint32_t uPos) +{ + QCBORError nReturn = QCBOR_SUCCESS; + + if(pNesting->pCurrentNesting == &pNesting->pArrays[QCBOR_MAX_ARRAY_NESTING]) { + // trying to open one too many + nReturn = QCBOR_ERR_ARRAY_NESTING_TOO_DEEP; + } else { + pNesting->pCurrentNesting++; + pNesting->pCurrentNesting->uCount = 0; + pNesting->pCurrentNesting->uStart = uPos; + pNesting->pCurrentNesting->uMajorType = uMajorType; + } + return nReturn; +} + +inline static void Nesting_Decrease(QCBORTrackNesting *pNesting) +{ + pNesting->pCurrentNesting--; +} + +inline static QCBORError Nesting_Increment(QCBORTrackNesting *pNesting) +{ + if(1 >= QCBOR_MAX_ITEMS_IN_ARRAY - pNesting->pCurrentNesting->uCount) { + return QCBOR_ERR_ARRAY_TOO_LONG; + } + + pNesting->pCurrentNesting->uCount += 1; + + return QCBOR_SUCCESS; +} + +inline static uint16_t Nesting_GetCount(QCBORTrackNesting *pNesting) +{ + // The nesting count recorded is always the actual number of individiual + // data items in the array or map. For arrays CBOR uses the actual item + // count. For maps, CBOR uses the number of pairs. This function returns + // the number needed for the CBOR encoding, so it divides the number of + // items by two for maps to get the number of pairs. This implementation + // takes advantage of the map major type being one larger the array major + // type, hence uDivisor is either 1 or 2. + const uint16_t uDivisor = pNesting->pCurrentNesting->uMajorType - CBOR_MAJOR_TYPE_ARRAY+1; + + return pNesting->pCurrentNesting->uCount / uDivisor; +} + +inline static uint32_t Nesting_GetStartPos(QCBORTrackNesting *pNesting) +{ + return pNesting->pCurrentNesting->uStart; +} + +inline static uint8_t Nesting_GetMajorType(QCBORTrackNesting *pNesting) +{ + return pNesting->pCurrentNesting->uMajorType; +} + +inline static int Nesting_IsInNest(QCBORTrackNesting *pNesting) +{ + return pNesting->pCurrentNesting == &pNesting->pArrays[0] ? 0 : 1; +} + + + + +/* + Error tracking plan -- Errors are tracked internally and not returned + until Finish is called. The CBOR errors are in me->uError. + UsefulOutBuf also tracks whether the buffer is full or not in its + context. Once either of these errors is set they are never + cleared. Only QCBOREncode_Init() resets them. Or said another way, they must + never be cleared or we'll tell the caller all is good when it is not. + + Only one error code is reported by QCBOREncode_Finish() even if there are + multiple errors. The last one set wins. The caller might have to fix + one error to reveal the next one they have to fix. This is OK. + + The buffer full error tracked by UsefulBuf is only pulled out of + UsefulBuf in Finish() so it is the one that usually wins. UsefulBuf + will never go off the end of the buffer even if it is called again + and again when full. + + It is really tempting to not check for overflow on the count in the + number of items in an array. It would save a lot of code, it is + extremely unlikely that any one will every put 65,000 items in an + array, and the only bad thing that would happen is the CBOR would be + bogus. + + Since this does not parse any input, you could in theory remove all + error checks in this code if you knew the caller called it + correctly. Maybe someday CDDL or some such language will be able to + generate the code to call this and the calling code would always be + correct. This could also automatically size some of the data + structures like array/map nesting resulting in some stack memory + savings. + + Errors returned here fall into two categories: + + Sizes + QCBOR_ERR_BUFFER_TOO_LARGE -- Encoded output exceeded UINT32_MAX + QCBOR_ERR_BUFFER_TOO_SMALL -- output buffer too small + + QCBOR_ERR_ARRAY_NESTING_TOO_DEEP -- Array/map nesting > QCBOR_MAX_ARRAY_NESTING1 + QCBOR_ERR_ARRAY_TOO_LONG -- Too many things added to an array/map + + Nesting constructed incorrectly + QCBOR_ERR_TOO_MANY_CLOSES -- more close calls than opens + QCBOR_ERR_CLOSE_MISMATCH -- Type of close does not match open + QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN -- Finish called without enough closes + */ + + + + +/* + Public function for initialization. See header qcbor.h + */ +void QCBOREncode_Init(QCBOREncodeContext *me, UsefulBuf Storage) +{ + memset(me, 0, sizeof(QCBOREncodeContext)); + UsefulOutBuf_Init(&(me->OutBuf), Storage); + Nesting_Init(&(me->nesting)); +} + + + + +/* + All CBOR data items have a type and an "argument". The argument is + either the value of the item for integer types, the length of the + content for string, byte, array and map types, a tag for major type + 6, and has several uses for major type 7. + + This function encodes the type and the argument. There are several + encodings for the argument depending on how large it is and how it is + used. + + Every encoding of the type and argument has at least one byte, the + "initial byte". + + The top three bits of the initial byte are the major type for the + CBOR data item. The eight major types defined by the standard are + defined as CBOR_MAJOR_TYPE_xxxx in qcbor.h. + + The remaining five bits, known as "additional information", and + possibly more bytes encode the argument. If the argument is less than + 24, then it is encoded entirely in the five bits. This is neat + because it allows you to encode an entire CBOR data item in 1 byte + for many values and types (integers 0-23, true, false, and tags). + + If the argument is larger than 24, then it is encoded in 1,2,4 or 8 + additional bytes, with the number of these bytes indicated by the + values of the 5 bits 24, 25, 25 and 27. + + It is possible to encode a particular argument in many ways with this + representation. This implementation always uses the smallest + possible representation. This conforms with CBOR preferred encoding. + + This function inserts them into the output buffer at the specified + position. AppendEncodedTypeAndNumber() appends to the end. + + This function takes care of converting to network byte order. + + This function is also used to insert floats and doubles. Before this + function is called the float or double must be copied into a + uint64_t. That is how they are passed in. They are then converted to + network byte order correctly. The uMinLen param makes sure that even + + if all the digits of a half, float or double are 0 it is still + correctly encoded in 2, 4 or 8 bytes. + */ + +static void InsertEncodedTypeAndNumber(QCBOREncodeContext *me, + uint8_t uMajorType, + int nMinLen, + uint64_t uNumber, + size_t uPos) +{ + /* + This code does endian conversion without hton or knowing the + endianness of the machine using masks and shifts. This avoids the + dependency on hton and the mess of figuring out how to find the + machine's endianness. + + This is a good efficient implementation on little-endian machines. + A faster and small implementation is possible on big-endian + machines because CBOR/network byte order is big endian. However + big endian machines are uncommon. + + On x86, it is about 200 bytes instead of 500 bytes for the more + formal unoptimized code. + + This also does the CBOR preferred shortest encoding for integers + and is called to do endian conversion for floats. + + It works backwards from the LSB to the MSB as needed. + + Code Reviewers: THIS FUNCTION DOES POINTER MATH + */ + // Holds up to 9 bytes of type and argument + // plus one extra so pointer always points to + // valid bytes. + uint8_t bytes[sizeof(uint64_t)+2]; + // Point to the last bytes and work backwards + uint8_t *pByte = &bytes[sizeof(bytes)-1]; + // This is the 5 bits in the initial byte that is not the major type + uint8_t uAdditionalInfo; + + if(uNumber < CBOR_TWENTY_FOUR && nMinLen == 0) { + // Simple case where argument is < 24 + uAdditionalInfo = uNumber; + } else { + /* + Encode argument in 1,2,4 or 8 bytes. Outer loop + runs once for 1 byte and 4 times for 8 bytes. + Inner loop runs 1, 2 or 4 times depending on + outer loop counter. This works backwards taking + 8 bits off the argument being encoded at a time + until all bits from uNumber have been encoded + and the minimum encoding size is reached. + Minimum encoding size is for floating point + numbers with zero bytes. + */ + static const uint8_t aIterate[] = {1,1,2,4}; + uint8_t i; + for(i = 0; uNumber || nMinLen > 0; i++) { + const uint8_t uIterations = aIterate[i]; + for(int j = 0; j < uIterations; j++) { + *--pByte = uNumber & 0xff; + uNumber = uNumber >> 8; + } + nMinLen -= uIterations; + } + // Additional info is the encoding of the + // number of additional bytes to encode + // argument. + uAdditionalInfo = LEN_IS_ONE_BYTE-1 + i; + } + *--pByte = (uMajorType << 5) + uAdditionalInfo; + + UsefulOutBuf_InsertData(&(me->OutBuf), pByte, &bytes[sizeof(bytes)-1] - pByte, uPos); +} + + +/* + Append the type and number info to the end of the buffer. + + See InsertEncodedTypeAndNumber() function above for details +*/ +inline static void AppendEncodedTypeAndNumber(QCBOREncodeContext *me, + uint8_t uMajorType, + uint64_t uNumber) +{ + // An append is an insert at the end. + InsertEncodedTypeAndNumber(me, + uMajorType, + 0, + uNumber, + UsefulOutBuf_GetEndPosition(&(me->OutBuf))); +} + + + + +/* + Public functions for closing arrays and maps. See header qcbor.h + */ +void QCBOREncode_AddUInt64(QCBOREncodeContext *me, uint64_t uValue) +{ + if(me->uError == QCBOR_SUCCESS) { + AppendEncodedTypeAndNumber(me, CBOR_MAJOR_TYPE_POSITIVE_INT, uValue); + me->uError = Nesting_Increment(&(me->nesting)); + } +} + + +/* + Public functions for closing arrays and maps. See header qcbor.h + */ +void QCBOREncode_AddInt64(QCBOREncodeContext *me, int64_t nNum) +{ + if(me->uError == QCBOR_SUCCESS) { + uint8_t uMajorType; + uint64_t uValue; + + if(nNum < 0) { + // In CBOR -1 encodes as 0x00 with major type negative int. + uValue = (uint64_t)(-nNum - 1); + uMajorType = CBOR_MAJOR_TYPE_NEGATIVE_INT; + } else { + uValue = (uint64_t)nNum; + uMajorType = CBOR_MAJOR_TYPE_POSITIVE_INT; + } + + AppendEncodedTypeAndNumber(me, uMajorType, uValue); + me->uError = Nesting_Increment(&(me->nesting)); + } +} + + +/* + Semi-private function. It is exposed to user of the interface, + but they will usually call one of the inline wrappers rather than this. + + See header qcbor.h + + Does the work of adding some bytes to the CBOR output. Works for a + byte and text strings, which are the same in in CBOR though they have + different major types. This is also used to insert raw + pre-encoded CBOR. + */ +void QCBOREncode_AddBuffer(QCBOREncodeContext *me, uint8_t uMajorType, UsefulBufC Bytes) +{ + if(me->uError == QCBOR_SUCCESS) { + // If it is not Raw CBOR, add the type and the length + if(uMajorType != CBOR_MAJOR_NONE_TYPE_RAW) { + AppendEncodedTypeAndNumber(me, uMajorType, Bytes.len); + } + + // Actually add the bytes + UsefulOutBuf_AppendUsefulBuf(&(me->OutBuf), Bytes); + + // Update the array counting if there is any nesting at all + me->uError = Nesting_Increment(&(me->nesting)); + } +} + + +/* + Public functions for closing arrays and maps. See header qcbor.h + */ +void QCBOREncode_AddTag(QCBOREncodeContext *me, uint64_t uTag) +{ + AppendEncodedTypeAndNumber(me, CBOR_MAJOR_TYPE_OPTIONAL, uTag); +} + + +/* + Semi-private function. It is exposed to user of the interface, + but they will usually call one of the inline wrappers rather than this. + + See header qcbor.h + */ +void QCBOREncode_AddType7(QCBOREncodeContext *me, size_t uSize, uint64_t uNum) +{ + if(me->uError == QCBOR_SUCCESS) { + // This function call takes care of endian swapping for the float / double + InsertEncodedTypeAndNumber(me, + // The major type for floats and doubles + CBOR_MAJOR_TYPE_SIMPLE, + // size makes sure floats with zeros encode correctly + (int)uSize, + // Bytes of the floating point number as a uint + uNum, + // end position because this is append + UsefulOutBuf_GetEndPosition(&(me->OutBuf))); + + me->uError = Nesting_Increment(&(me->nesting)); + } +} + + +/* + Public functions for closing arrays and maps. See header qcbor.h + */ +void QCBOREncode_AddDouble(QCBOREncodeContext *me, double dNum) +{ + const IEEE754_union uNum = IEEE754_DoubleToSmallest(dNum); + + QCBOREncode_AddType7(me, uNum.uSize, uNum.uValue); +} + + +/* + Semi-public function. It is exposed to user of the interface, + but they will usually call one of the inline wrappers rather than this. + + See header qcbor.h +*/ +void QCBOREncode_OpenMapOrArray(QCBOREncodeContext *me, uint8_t uMajorType) +{ + // Add one item to the nesting level we are in for the new map or array + me->uError = Nesting_Increment(&(me->nesting)); + if(me->uError == QCBOR_SUCCESS) { + // The offset where the length of an array or map will get written + // is stored in a uint32_t, not a size_t to keep stack usage smaller. This + // checks to be sure there is no wrap around when recording the offset. + // Note that on 64-bit machines CBOR larger than 4GB can be encoded as long as no + // array / map offsets occur past the 4GB mark, but the public interface + // says that the maximum is 4GB to keep the discussion simpler. + size_t uEndPosition = UsefulOutBuf_GetEndPosition(&(me->OutBuf)); + + // QCBOR_MAX_ARRAY_OFFSET is slightly less than UINT32_MAX so this + // code can run on a 32-bit machine and tests can pass on a 32-bit + // machine. If it was exactly UINT32_MAX, then this code would + // not compile or run on a 32-bit machine and an #ifdef or some + // machine size detection would be needed reducing portability. + if(uEndPosition >= QCBOR_MAX_ARRAY_OFFSET) { + me->uError = QCBOR_ERR_BUFFER_TOO_LARGE; + + } else { + // Increase nesting level because this is a map or array. + // Cast from size_t to uin32_t is safe because of check above + me->uError = Nesting_Increase(&(me->nesting), uMajorType, (uint32_t)uEndPosition); + } + } +} + + +/* + Public functions for closing arrays and maps. See header qcbor.h + */ +void QCBOREncode_CloseMapOrArray(QCBOREncodeContext *me, + uint8_t uMajorType, + UsefulBufC *pWrappedCBOR) +{ + if(me->uError == QCBOR_SUCCESS) { + if(!Nesting_IsInNest(&(me->nesting))) { + me->uError = QCBOR_ERR_TOO_MANY_CLOSES; + } else if(Nesting_GetMajorType(&(me->nesting)) != uMajorType) { + me->uError = QCBOR_ERR_CLOSE_MISMATCH; + } else { + // When the array, map or bstr wrap was started, nothing was done + // except note the position of the start of it. This code goes back + // and inserts the actual CBOR array, map or bstr and its length. + // That means all the data that is in the array, map or wrapped + // needs to be slid to the right. This is done by UsefulOutBuf's + // insert function that is called from inside + // InsertEncodedTypeAndNumber() + const size_t uInsertPosition = Nesting_GetStartPos(&(me->nesting)); + const size_t uEndPosition = UsefulOutBuf_GetEndPosition(&(me->OutBuf)); + // This can't go negative because the UsefulOutBuf always only grows + // and never shrinks. UsefulOutBut itself also has defenses such that + // it won't write were it should not even if given hostile input lengths + const size_t uLenOfEncodedMapOrArray = uEndPosition - uInsertPosition; + + // Length is number of bytes for a bstr and number of items a for map & array + const size_t uLength = uMajorType == CBOR_MAJOR_TYPE_BYTE_STRING ? + uLenOfEncodedMapOrArray : Nesting_GetCount(&(me->nesting)); + + // Actually insert + InsertEncodedTypeAndNumber(me, + uMajorType, // major type bstr, array or map + 0, // no minimum length for encoding + uLength, // either len of bstr or num map / array items + uInsertPosition); // position in out buffer + + // Return pointer and length to the enclosed encoded CBOR. The intended + // use is for it to be hashed (e.g., SHA-256) in a COSE implementation. + // This must be used right away, as the pointer and length go invalid + // on any subsequent calls to this function because of the + // InsertEncodedTypeAndNumber() call that slides data to the right. + if(pWrappedCBOR) { + const UsefulBufC PartialResult = UsefulOutBuf_OutUBuf(&(me->OutBuf)); + const size_t uBstrLen = UsefulOutBuf_GetEndPosition(&(me->OutBuf)) - uEndPosition; + *pWrappedCBOR = UsefulBuf_Tail(PartialResult, uInsertPosition+uBstrLen); + } + Nesting_Decrease(&(me->nesting)); + } + } +} + + + + +/* + Public functions to finish and get the encoded result. See header qcbor.h + */ +QCBORError QCBOREncode_Finish(QCBOREncodeContext *me, UsefulBufC *pEncodedCBOR) +{ + QCBORError uReturn = me->uError; + + if(uReturn != QCBOR_SUCCESS) { + goto Done; + } + + if (Nesting_IsInNest(&(me->nesting))) { + uReturn = QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN; + goto Done; + } + + if(UsefulOutBuf_GetError(&(me->OutBuf))) { + // Stuff didn't fit in the buffer. + // This check catches this condition for all the appends and inserts + // so checks aren't needed when the appends and inserts are performed. + // And of course UsefulBuf will never overrun the input buffer given + // to it. No complex analysis of the error handling in this file is + // needed to know that is true. Just read the UsefulBuf code. + uReturn = QCBOR_ERR_BUFFER_TOO_SMALL; + goto Done; + } + + *pEncodedCBOR = UsefulOutBuf_OutUBuf(&(me->OutBuf)); + +Done: + return uReturn; +} + + +/* + Public functions to finish and get the encoded result. See header qcbor.h + */ +QCBORError QCBOREncode_FinishGetSize(QCBOREncodeContext *me, size_t *puEncodedLen) +{ + UsefulBufC Enc; + + QCBORError nReturn = QCBOREncode_Finish(me, &Enc); + + if(nReturn == QCBOR_SUCCESS) { + *puEncodedLen = Enc.len; + } + + return nReturn; +} + + + + +/* + Notes on the code + + CBOR Major Type Public Function + 0 QCBOREncode_AddUInt64 + 0, 1 QCBOREncode_AddUInt64, QCBOREncode_AddInt64 + 2, 3 QCBOREncode_AddBuffer, Also QCBOREncode_OpenMapOrArray + 4, 5 QCBOREncode_OpenMapOrArray + 6 QCBOREncode_AddTag + 7 QCBOREncode_AddDouble, QCBOREncode_AddType7 + + Object code sizes on X86 with LLVM compiler and -Os (Dec 30, 2018) + + _QCBOREncode_Init 69 + _QCBOREncode_AddUInt64 76 + _QCBOREncode_AddInt64 87 + _QCBOREncode_AddBuffer 113 + _QCBOREncode_AddTag 27 + _QCBOREncode_AddType7 87 + _QCBOREncode_AddDouble 36 + _QCBOREncode_OpenMapOrArray 103 + _QCBOREncode_CloseMapOrArray 181 + _InsertEncodedTypeAndNumber 190 + _QCBOREncode_Finish 72 + _QCBOREncode_FinishGetSize 70 + + Total is about 1.1KB + + _QCBOREncode_CloseMapOrArray is larger because it has a lot + of nesting tracking to do and much of Nesting_ inlines + into it. It probably can't be reduced much. + + If the error returned by Nesting_Increment() can be ignored + because the limit is so high and the consequence of exceeding + is proved to be inconsequential, then a lot of if(me->uError) + instance can be removed, saving some code. + + */ + diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/qcbor/test/UsefulBuf_Tests.c b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/qcbor/test/UsefulBuf_Tests.c new file mode 100644 index 0000000..c0568b4 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/qcbor/test/UsefulBuf_Tests.c @@ -0,0 +1,701 @@ +/*============================================================================== + Copyright (c) 2016-2018, The Linux Foundation. + Copyright (c) 2018-2019, Laurence Lundblade. + All rights reserved. + SPDX-License-Identifier: BSD-3-Clause + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of The Linux Foundation nor the names of its + contributors, nor the name "Laurence Lundblade" may be used to + endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ==============================================================================*/ + +#include "UsefulBuf.h" + + +/* Basic exercise... + + Call all the main public functions. + + Binary compare the result to the expected. + + There is nothing adversarial in this test + */ +const char * UOBTest_NonAdversarial() +{ + const char *szReturn = NULL; + + UsefulBuf_MAKE_STACK_UB(outbuf,50); + + UsefulOutBuf UOB; + + UsefulOutBuf_Init(&UOB, outbuf); + + if(!UsefulOutBuf_AtStart(&UOB)) { + szReturn = "Not at start"; + goto Done; + } + + // Put 7 bytes at beginning of buf + UsefulOutBuf_AppendData(&UOB, "bluster", 7); + + if(UsefulOutBuf_AtStart(&UOB)) { + szReturn = "At start"; + goto Done; + } + + // add a space to end + UsefulOutBuf_AppendByte(&UOB, ' '); + + // Add 5 bytes to the end + UsefulBufC UBC = {"hunny", 5}; + UsefulOutBuf_AppendUsefulBuf(&UOB, UBC); + + // Insert 9 bytes at the beginning, slide the previous stuff right + UsefulOutBuf_InsertData(&UOB, "heffalump", 9, 0); + UsefulOutBuf_InsertByte(&UOB, ' ', 9); + + // Put 9 bytes in at position 10 -- just after "heffalump " + UsefulBufC UBC2 = {"unbounce ", 9}; + UsefulOutBuf_InsertUsefulBuf(&UOB, UBC2, 10); + + // Make it a null terminated string (because all the appends and inserts above not strcpy !) + UsefulOutBuf_AppendByte(&UOB, '\0'); + + + UsefulBufC U = UsefulOutBuf_OutUBuf(&UOB); + + const char *expected = "heffalump unbounce bluster hunny"; + + if(UsefulBuf_IsNULLC(U) || U.len-1 != strlen(expected) || strcmp(expected, U.ptr) || UsefulOutBuf_GetError(&UOB)) { + szReturn = "OutUBuf"; + } + + UsefulBuf_MAKE_STACK_UB(buf, 50); + UsefulBufC Out = UsefulOutBuf_CopyOut(&UOB, buf); + + if(UsefulBuf_IsNULLC(Out) || Out.len-1 != strlen(expected) || strcmp(expected, Out.ptr)) { + szReturn = "CopyOut"; + } + +Done: + return szReturn; +} + + +/* + Append test utility. + pUOB is the buffer to append too + num is the amount to append + expected is the expected return code, 0 or 1 + + returns 0 if test passed + + */ +static int AppendTest(UsefulOutBuf *pUOB, size_t num, int expected) +{ + //reset + UsefulOutBuf_Reset(pUOB); + + // check status first + if(UsefulOutBuf_GetError(pUOB)) + return 1; + + // append the bytes + UsefulOutBuf_AppendData(pUOB, (const uint8_t *)"bluster", num); + + // check error status after + if(UsefulOutBuf_GetError(pUOB) != expected) + return 1; + + return 0; +} + + +/* + Same as append, but takes a position param too + */ +static int InsertTest(UsefulOutBuf *pUOB, size_t num, size_t pos, int expected) +{ + // reset + UsefulOutBuf_Reset(pUOB); + + // check + if(UsefulOutBuf_GetError(pUOB)) + return 1; + + UsefulOutBuf_InsertData(pUOB, (const uint8_t *)"bluster", num, pos); + + if(UsefulOutBuf_GetError(pUOB) != expected) + return 1; + + return 0; +} + + +/* + Boundary conditions to test + - around 0 + - around the buffer size + - around MAX size_t + + + Test these for the buffer size and the cursor, the insert amount, the append amount and the insert position + + */ + +const char *UOBTest_BoundaryConditionsTest() +{ + UsefulBuf_MAKE_STACK_UB(outbuf,2); + + UsefulOutBuf UOB; + + UsefulOutBuf_Init(&UOB, outbuf); + + // append 0 byte to a 2 byte buffer --> success + if(AppendTest(&UOB, 0, 0)) + return "Append 0 bytes failed"; + + // append 1 byte to a 2 byte buffer --> success + if(AppendTest(&UOB, 1, 0)) + return "Append of 1 byte failed"; + + // append 2 byte to a 2 byte buffer --> success + if(AppendTest(&UOB, 2, 0)) + return "Append to fill buffer failed"; + + // append 3 bytes to a 2 byte buffer --> failure + if(AppendTest(&UOB, 3, 1)) + return "Overflow of buffer not caught"; + + // append max size_t to a 2 byte buffer --> failure + if(AppendTest(&UOB, SIZE_MAX, 1)) + return "Append of SIZE_MAX error not caught"; + + if(InsertTest(&UOB, 1, 0, 0)) + return "Insert 1 byte at start failed"; + + if(InsertTest(&UOB, 2, 0, 0)) + return "Insert 2 bytes at start failed"; + + if(InsertTest(&UOB, 3, 0, 1)) + return "Insert overflow not caught"; + + if(InsertTest(&UOB, 1, 1, 1)) + return "Bad insertion point not caught"; + + + UsefulBuf_MAKE_STACK_UB(outBuf2,10); + + UsefulOutBuf_Init(&UOB, outBuf2); + + UsefulOutBuf_Reset(&UOB); + // put data in the buffer + UsefulOutBuf_AppendString(&UOB, "abc123"); + + UsefulOutBuf_InsertString(&UOB, "xyz*&^", 0); + + if(!UsefulOutBuf_GetError(&UOB)) { + return "insert with data should have failed"; + } + + + UsefulOutBuf_Init(&UOB, (UsefulBuf){NULL, SIZE_MAX - 5}); + UsefulOutBuf_AppendData(&UOB, "123456789", SIZE_MAX -6); + if(UsefulOutBuf_GetError(&UOB)) { + return "insert in huge should have succeeded"; + } + + UsefulOutBuf_Init(&UOB, (UsefulBuf){NULL, SIZE_MAX - 5}); + UsefulOutBuf_AppendData(&UOB, "123456789", SIZE_MAX -5); + if(UsefulOutBuf_GetError(&UOB)) { + return "insert in huge should have succeeded"; + } + + UsefulOutBuf_Init(&UOB, (UsefulBuf){NULL, SIZE_MAX - 5}); + UsefulOutBuf_AppendData(&UOB, "123456789", SIZE_MAX - 4); + if(!UsefulOutBuf_GetError(&UOB)) { + return "lengths near max size"; + } + + return NULL; +} + + + + + +// Test function to get size and magic number check + +const char *TestBasicSanity() +{ + UsefulBuf_MAKE_STACK_UB(outbuf,10); + + UsefulOutBuf UOB; + + // First -- make sure that the room left function returns the right amount + UsefulOutBuf_Init(&UOB, outbuf); + + if(UsefulOutBuf_RoomLeft(&UOB) != 10) + return "room left failed"; + + if(!UsefulOutBuf_WillItFit(&UOB, 9)) { + return "it did not fit"; + } + + if(UsefulOutBuf_WillItFit(&UOB, 11)) { + return "it should have not fit"; + } + + + // Next -- make sure that the magic number checking is working right + UOB.magic = 8888; // make magic bogus + + UsefulOutBuf_AppendData(&UOB, (const uint8_t *)"bluster", 7); + + if(!UsefulOutBuf_GetError(&UOB)) + return "magic corruption check failed"; + + + + // Next make sure that the valid data length check is working right + UsefulOutBuf_Init(&UOB, outbuf); + + UOB.data_len = UOB.UB.len+1; // make size bogus + + UsefulOutBuf_AppendData(&UOB, (const uint8_t *)"bluster", 7); + if(!UsefulOutBuf_GetError(&UOB)) + return "valid data check failed"; + + return NULL; +} + + + +const char *UBMacroConversionsTest() +{ + char *szFoo = "foo"; + + UsefulBufC Foo = UsefulBuf_FromSZ(szFoo); + if(Foo.len != 3 || strncmp(Foo.ptr, szFoo, 3)) + return "SZToUsefulBufC failed"; + + UsefulBufC Too = UsefulBuf_FROM_SZ_LITERAL("Toooo"); + if(Too.len != 5 || strncmp(Too.ptr, "Toooo", 5)) + return "UsefulBuf_FROM_SZ_LITERAL failed"; + + uint8_t pB[] = {0x42, 0x6f, 0x6f}; + UsefulBufC Boo = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pB); + if(Boo.len != 3 || strncmp(Boo.ptr, "Boo", 3)) + return "UsefulBuf_FROM_BYTE_ARRAY_LITERAL failed"; + + char *sz = "not const"; // some data for the test + UsefulBuf B = (UsefulBuf){sz, sizeof(sz)}; + UsefulBufC BC = UsefulBuf_Const(B); + if(BC.len != sizeof(sz) || BC.ptr != sz) + return "UsefulBufConst failed"; + + return NULL; +} + + +const char *UBUtilTests() +{ + UsefulBuf UB = NULLUsefulBuf; + + if(!UsefulBuf_IsNULL(UB)){ + return "IsNull failed"; + } + + if(!UsefulBuf_IsEmpty(UB)){ + return "IsEmpty failed"; + } + + if(!UsefulBuf_IsNULLOrEmpty(UB)) { + return "IsNULLOrEmpty failed"; + } + + const UsefulBufC UBC = UsefulBuf_Const(UB); + + if(!UsefulBuf_IsNULLC(UBC)){ + return "IsNull const failed"; + } + + if(!UsefulBuf_IsEmptyC(UBC)){ + return "IsEmptyC failed"; + } + + if(!UsefulBuf_IsNULLOrEmptyC(UBC)){ + return "IsNULLOrEmptyC failed"; + } + + const UsefulBuf UB2 = UsefulBuf_Unconst(UBC); + if(!UsefulBuf_IsEmpty(UB2)) { + return "Back to UB is Empty failed"; + } + + UB.ptr = "x"; // just some valid pointer + + if(UsefulBuf_IsNULL(UB)){ + return "IsNull failed"; + } + + if(!UsefulBuf_IsEmptyC(UBC)){ + return "IsEmpty failed"; + } + + // test the Unconst. + if(UsefulBuf_Unconst(UBC).ptr != NULL) { + return "Unconst failed"; + } + + // Set 100 bytes of '+'; validated a few tests later + UsefulBuf_MAKE_STACK_UB(Temp, 100); + const UsefulBufC TempC = UsefulBuf_Set(Temp, '+'); + + // Try to copy into a buf that is too small and see failure + UsefulBuf_MAKE_STACK_UB(Temp2, 99); + if(!UsefulBuf_IsNULLC(UsefulBuf_Copy(Temp2, TempC))) { + return "Copy should have failed"; + } + + if(UsefulBuf_IsNULLC(UsefulBuf_CopyPtr(Temp2, "xx", 2))) { + return "CopyPtr failed"; + } + + UsefulBufC xxyy = UsefulBuf_CopyOffset(Temp2, 2, UsefulBuf_FROM_SZ_LITERAL("yy")); + if(UsefulBuf_IsNULLC(xxyy)) { + return "CopyOffset Failed"; + } + + if(UsefulBuf_Compare(UsefulBuf_Head(xxyy, 3), UsefulBuf_FROM_SZ_LITERAL("xxy"))) { + return "head failed"; + } + + if(UsefulBuf_Compare(UsefulBuf_Tail(xxyy, 1), UsefulBuf_FROM_SZ_LITERAL("xyy"))) { + return "tail failed"; + } + + if(!UsefulBuf_IsNULLC(UsefulBuf_Head(xxyy, 5))) { + return "head should have failed"; + } + + if(!UsefulBuf_IsNULLC(UsefulBuf_Tail(xxyy, 5))) { + return "tail should have failed"; + } + + if(!UsefulBuf_IsNULLC(UsefulBuf_Tail(NULLUsefulBufC, 0))) { + return "tail of NULLUsefulBufC is not NULLUsefulBufC"; + } + + const UsefulBufC TailResult = UsefulBuf_Tail((UsefulBufC){NULL, 100}, 99); + if(TailResult.ptr != NULL || TailResult.len != 1) { + return "tail of NULL and length incorrect"; + } + + if(!UsefulBuf_IsNULLC(UsefulBuf_CopyOffset(Temp2, 100, UsefulBuf_FROM_SZ_LITERAL("yy")))) { + return "Copy Offset should have failed"; + } + + // Try to copy into a NULL/empty buf and see failure + const UsefulBuf UBNull = NULLUsefulBuf; + if(!UsefulBuf_IsNULLC(UsefulBuf_Copy(UBNull, TempC))) { + return "Copy to NULL should have failed"; + } + + + // Try to set a NULL/empty buf; nothing should happen + UsefulBuf_Set(UBNull, '+'); // This will crash on failure + + // Copy successfully to a buffer + UsefulBuf_MAKE_STACK_UB(Temp3, 101); + if(UsefulBuf_IsNULLC(UsefulBuf_Copy(Temp3, TempC))) { + return "Copy should not have failed"; + } + + static const uint8_t pExpected[] = { + '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', + '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', + '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', + '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', + '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', + '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', + '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', + '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', + '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', + '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', + }; + UsefulBufC Expected = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pExpected); + // This validates comparison for equality and the UsefulBuf_Set + if(UsefulBuf_Compare(Expected, TempC)) { + return "Set / Copy / Compare failed"; + } + + // Compare two empties and expect success + if(UsefulBuf_Compare(NULLUsefulBufC, NULLUsefulBufC)){ + return "Compare Empties failed"; + } + + // Compare with empty and expect the first to be larger + if(UsefulBuf_Compare(Expected, NULLUsefulBufC) <= 0){ + return "Compare with empty failed"; + } + + + static const uint8_t pExpectedBigger[] = { + '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', + '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', + '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', + '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', + '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', + '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', + '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', + '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', + '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', + '+', '+', '+', '+', '+', '+', '+', '+', '+', ',', + }; + const UsefulBufC ExpectedBigger = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pExpectedBigger); + + // Expect -1 when the first arg is smaller + if(UsefulBuf_Compare(Expected, ExpectedBigger) >= 0){ + return "Compare with bigger"; + } + + + static const uint8_t pExpectedSmaller[] = { + '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', + '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', + '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', + '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', + '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', + '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', + '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', + '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', + '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', + '+', '+', '+', '+', '+', '+', '+', '+', '+', '*', + }; + const UsefulBufC ExpectedSmaller = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pExpectedSmaller); + // Expect +1 when the first arg is larger + if(UsefulBuf_Compare(Expected, ExpectedSmaller) <= 0){ + return "Compare with smaller"; + } + + + static const uint8_t pExpectedLonger[] = { + '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', + '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', + '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', + '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', + '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', + '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', + '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', + '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', + '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', + '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', '+' + }; + const UsefulBufC ExpectedLonger = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pExpectedLonger); + + // Expect -1 when the first arg is smaller + if(UsefulBuf_Compare(Expected, ExpectedLonger) >= 0){ + return "Compare with longer"; + } + + + static const uint8_t pExpectedShorter[] = { + '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', + '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', + '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', + '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', + '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', + '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', + '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', + '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', + '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', + '+', '+', '+', '+', '+', '+', '+', '+', '+', + }; + const UsefulBufC ExpectedShorter = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pExpectedShorter); + // Expect +1 with the first arg is larger + if(UsefulBuf_Compare(Expected, ExpectedShorter) <= 0){ + return "Compare with shorter"; + } + + + if(UsefulBuf_IsNULLC(UsefulBuf_Copy(Temp, NULLUsefulBufC))) { + return "Copy null/empty failed"; + } + + // Look for +++++... in +++++... and find it at the beginning + if(0 != UsefulBuf_FindBytes(ExpectedLonger, ExpectedShorter)){ + return "Failed to find"; + } + + // look for ++* in ....++* and find it at the end + static const uint8_t pToFind[] = {'+', '+', '*'}; + const UsefulBufC ToBeFound = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pToFind); + + if(97 != UsefulBuf_FindBytes(ExpectedSmaller, ToBeFound)){ + return "Failed to find 2"; + } + + // look for ++* in ....++, and find it near the end + if(SIZE_MAX != UsefulBuf_FindBytes(ExpectedBigger, ToBeFound)){ + return "Failed to not find"; + } + + // Look for the whole buffer in itself and succeed. + if(0 != UsefulBuf_FindBytes(ExpectedLonger, ExpectedLonger)){ + return "Failed to find 3"; + } + + return NULL; +} + + +const char * UIBTest_IntegerFormat() +{ + UsefulOutBuf_MakeOnStack(UOB,100); + + const uint32_t u32 = 0x0A0B0C0D; // from https://en.wikipedia.org/wiki/Endianness + const uint64_t u64 = 1984738472938472; + const uint16_t u16 = 40000; + const uint8_t u8 = 9; + const float f = (float)314.15; + const double d = 2.1e10; + + + UsefulOutBuf_AppendUint32(&UOB, u32); // Also tests UsefulOutBuf_InsertUint64 and UsefulOutBuf_GetEndPosition + UsefulOutBuf_AppendUint64(&UOB, u64); // Also tests UsefulOutBuf_InsertUint32 + UsefulOutBuf_AppendUint16(&UOB, u16); // Also tests UsefulOutBuf_InsertUint16 + UsefulOutBuf_AppendByte(&UOB, u8); + UsefulOutBuf_AppendFloat(&UOB, f); // Also tests UsefulOutBuf_InsertFloat + UsefulOutBuf_AppendDouble(&UOB, d); // Also tests UsefulOutBuf_InsertDouble + + const UsefulBufC O = UsefulOutBuf_OutUBuf(&UOB); + if(UsefulBuf_IsNULLC(O)) + return "Couldn't output integers"; + + // from https://en.wikipedia.org/wiki/Endianness + const uint8_t pExpectedNetworkOrder[4] = {0x0A, 0x0B, 0x0C, 0x0D}; + if(memcmp(O.ptr, pExpectedNetworkOrder, 4)) { + return "not in network order"; + } + + UsefulInputBuf UIB; + + UsefulInputBuf_Init(&UIB, O); + + if(UsefulInputBuf_Tell(&UIB) != 0) { + return "UsefulInputBuf_Tell failed"; + } + + if(UsefulInputBuf_GetUint32(&UIB) != u32) { + return "u32 out then in failed"; + } + if(UsefulInputBuf_GetUint64(&UIB) != u64) { + return "u64 out then in failed"; + } + if(UsefulInputBuf_GetUint16(&UIB) != u16) { + return "u16 out then in failed"; + } + if(UsefulInputBuf_GetByte(&UIB) != u8) { + return "u8 out then in failed"; + } + if(UsefulInputBuf_GetFloat(&UIB) != f) { + return "float out then in failed"; + } + if(UsefulInputBuf_GetDouble(&UIB) != d) { + return "double out then in failed"; + } + + // Reset and go again for a few more tests + UsefulInputBuf_Init(&UIB, O); + + const UsefulBufC Four = UsefulInputBuf_GetUsefulBuf(&UIB, 4); + if(UsefulBuf_IsNULLC(Four)) { + return "Four is NULL"; + } + if(UsefulBuf_Compare(Four, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pExpectedNetworkOrder))) { + return "Four compare failed"; + } + + if(UsefulInputBuf_BytesUnconsumed(&UIB) != 23){ + return "Wrong number of unconsumed bytes"; + } + + if(!UsefulInputBuf_BytesAvailable(&UIB, 23)){ + return "Wrong number of bytes available I"; + } + + if(UsefulInputBuf_BytesAvailable(&UIB, 24)){ + return "Wrong number of bytes available II"; + } + + UsefulInputBuf_Seek(&UIB, 0); + + if(UsefulInputBuf_GetError(&UIB)) { + return "unexpected error after seek"; + } + + const uint8_t *pGetBytes = (const uint8_t *)UsefulInputBuf_GetBytes(&UIB, 4); + if(pGetBytes == NULL) { + return "GetBytes returns NULL"; + } + + if(memcmp(pGetBytes, pExpectedNetworkOrder, 4)) { + return "Got wrong bytes"; + } + + UsefulInputBuf_Seek(&UIB, 28); + + if(!UsefulInputBuf_GetError(&UIB)) { + return "expected error after seek"; + } + + return NULL; +} + + +const char *UBUTest_CopyUtil() +{ + if(UsefulBufUtil_CopyFloatToUint32(65536.0F) != 0x47800000) { + return "CopyFloatToUint32 failed"; + } + + if(UsefulBufUtil_CopyDoubleToUint64(4e-40L) != 0X37C16C2800000000ULL) { + return "CopyDoubleToUint64 failed"; + } + + if(UsefulBufUtil_CopyUint64ToDouble(0X37C16C2800000000ULL) != 4e-40L) { + return "CopyUint64ToDouble failed"; + } + + if(UsefulBufUtil_CopyUint32ToFloat(0x47800000) != 65536.0F) { + return "CopyUint32ToFloat failed"; + } + + return NULL; +} + + + diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/qcbor/test/UsefulBuf_Tests.h b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/qcbor/test/UsefulBuf_Tests.h new file mode 100644 index 0000000..d85b951 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/qcbor/test/UsefulBuf_Tests.h @@ -0,0 +1,51 @@ +/*============================================================================== + Copyright (c) 2016-2018, The Linux Foundation. + Copyright (c) 2018, Laurence Lundblade. + All rights reserved. + SPDX-License-Identifier: BSD-3-Clause + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of The Linux Foundation nor the names of its + contributors, nor the name "Laurence Lundblade" may be used to + endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ==============================================================================*/ + +#ifndef UsefulBuf_UsefulBuf_Tests_h +#define UsefulBuf_UsefulBuf_Tests_h + +const char * UOBTest_NonAdversarial(void); + +const char * TestBasicSanity(void); + +const char * UOBTest_BoundaryConditionsTest(void); + +const char * UBMacroConversionsTest(void); + +const char * UBUtilTests(void); + +const char * UIBTest_IntegerFormat(void); + +const char * UBUTest_CopyUtil(void); + +#endif diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/qcbor/test/float_tests.c b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/qcbor/test/float_tests.c new file mode 100644 index 0000000..dd211c3 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/qcbor/test/float_tests.c @@ -0,0 +1,474 @@ +/*============================================================================== + float_tests.c -- tests for float and conversion to/from half-precision + + Copyright (c) 2018-2019, Laurence Lundblade. All rights reserved. + + SPDX-License-Identifier: BSD-3-Clause + + See BSD-3-Clause license in README.md + + Created on 9/19/18 + ==============================================================================*/ + +#include "float_tests.h" +#include "qcbor.h" +#include "half_to_double_from_rfc7049.h" +#include // For INFINITY and NAN and isnan() + + + +static const uint8_t spExpectedHalf[] = { + 0xB1, + 0x64, + 0x7A, 0x65, 0x72, 0x6F, + 0xF9, 0x00, 0x00, // 0.000 + 0x6A, + 0x69, 0x6E, 0x66, 0x69, 0x6E, 0x69, 0x74, 0x69, 0x74, 0x79, + 0xF9, 0x7C, 0x00, // Infinity + 0x73, + 0x6E, 0x65, 0x67, 0x61, 0x74, 0x69, 0x76, 0x65, 0x20, 0x69, 0x6E, 0x66, 0x69, 0x6E, 0x69, 0x74, 0x69, 0x74, 0x79, + 0xF9, 0xFC, 0x00, // -Inifinity + 0x63, + 0x4E, 0x61, 0x4E, + 0xF9, 0x7E, 0x00, // NaN + 0x63, + 0x6F, 0x6E, 0x65, + 0xF9, 0x3C, 0x00, // 1.0 + 0x69, + 0x6F, 0x6E, 0x65, 0x20, 0x74, 0x68, 0x69, 0x72, 0x64, + 0xF9, 0x35, 0x55, // 0.333251953125 + 0x76, + 0x6C, 0x61, 0x72, 0x67, 0x65, 0x73, 0x74, 0x20, 0x68, 0x61, 0x6C, 0x66, 0x2D, 0x70, 0x72, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6F, 0x6E, + 0xF9, 0x7B, 0xFF, // 65504.0 + 0x78, 0x18, 0x74, 0x6F, 0x6F, 0x2D, 0x6C, 0x61, 0x72, 0x67, 0x65, 0x20, 0x68, 0x61, 0x6C, 0x66, 0x2D, 0x70, 0x72, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6F, 0x6E, + 0xF9, 0x7C, 0x00, // Infinity + 0x72, + 0x73, 0x6D, 0x61, 0x6C, 0x6C, 0x65, 0x73, 0x74, 0x20, 0x73, 0x75, 0x62, 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C, + 0xF9, 0x00, 0x01, // 0.000000059604 + 0x6F, + 0x73, 0x6D, 0x61, 0x6C, 0x6C, 0x65, 0x73, 0x74, 0x20, 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C, + 0xF9, 0x03, 0xFF, // 0.0000609755516 + 0x71, + 0x62, 0x69, 0x67, 0x67, 0x65, 0x73, 0x74, 0x20, 0x73, 0x75, 0x62, 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C, + 0xF9, 0x04, 0x00, // 0.000061988 + 0x70, + 0x73, 0x75, 0x62, 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C, 0x20, 0x73, 0x69, 0x6E, 0x67, 0x6C, 0x65, + 0xF9, 0x00, 0x00, + 0x03, + 0xF9, 0xC0, 0x00, // -2 + 0x04, + 0xF9, 0x7E, 0x00, // qNaN + 0x05, + 0xF9, 0x7C, 0x01, // sNaN + 0x06, + 0xF9, 0x7E, 0x0F, // qNaN with payload 0x0f + 0x07, + 0xF9, 0x7C, 0x0F, // sNaN with payload 0x0f + +}; + + +int HalfPrecisionDecodeBasicTests() +{ + UsefulBufC HalfPrecision = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedHalf); + + QCBORDecodeContext DC; + QCBORDecode_Init(&DC, HalfPrecision, 0); + + QCBORItem Item; + + QCBORDecode_GetNext(&DC, &Item); + if(Item.uDataType != QCBOR_TYPE_MAP) { + return -1; + } + + QCBORDecode_GetNext(&DC, &Item); + if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 0.0F) { + return -2; + } + + QCBORDecode_GetNext(&DC, &Item); + if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != INFINITY) { + return -3; + } + + QCBORDecode_GetNext(&DC, &Item); + if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != -INFINITY) { + return -4; + } + + QCBORDecode_GetNext(&DC, &Item); // TODO, is this really converting right? It is carrying payload, but this confuses things. + if(Item.uDataType != QCBOR_TYPE_DOUBLE || !isnan(Item.val.dfnum)) { + return -5; + } + + QCBORDecode_GetNext(&DC, &Item); + if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 1.0F) { + return -6; + } + + QCBORDecode_GetNext(&DC, &Item); + if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 0.333251953125F) { + return -7; + } + + QCBORDecode_GetNext(&DC, &Item); + if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 65504.0F) { + return -8; + } + + QCBORDecode_GetNext(&DC, &Item); + if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != INFINITY) { + return -9; + } + + QCBORDecode_GetNext(&DC, &Item); // TODO: check this + if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 0.0000000596046448F) { + return -10; + } + + QCBORDecode_GetNext(&DC, &Item); // TODO: check this + if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 0.0000609755516F) { + return -11; + } + + QCBORDecode_GetNext(&DC, &Item); // TODO check this + if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 0.0000610351563F) { + return -12; + } + + QCBORDecode_GetNext(&DC, &Item); + if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 0) { + return -13; + } + + QCBORDecode_GetNext(&DC, &Item); + if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != -2.0F) { + return -14; + } + + // TODO: double check these four tests + QCBORDecode_GetNext(&DC, &Item); // qNaN + if(Item.uDataType != QCBOR_TYPE_DOUBLE || UsefulBufUtil_CopyDoubleToUint64(Item.val.dfnum) != 0x7ff8000000000000ULL) { + return -15; + } + QCBORDecode_GetNext(&DC, &Item); // sNaN + if(Item.uDataType != QCBOR_TYPE_DOUBLE || UsefulBufUtil_CopyDoubleToUint64(Item.val.dfnum) != 0x7ff0000000000001ULL) { + return -16; + } + QCBORDecode_GetNext(&DC, &Item); // qNaN with payload 0x0f + if(Item.uDataType != QCBOR_TYPE_DOUBLE || UsefulBufUtil_CopyDoubleToUint64(Item.val.dfnum) != 0x7ff800000000000fULL) { + return -17; + } + QCBORDecode_GetNext(&DC, &Item); // sNaN with payload 0x0f + if(Item.uDataType != QCBOR_TYPE_DOUBLE || UsefulBufUtil_CopyDoubleToUint64(Item.val.dfnum) != 0x7ff000000000000fULL) { + return -18; + } + + if(QCBORDecode_Finish(&DC)) { + return -19; + } + + return 0; +} + + + + +int HalfPrecisionAgainstRFCCodeTest() +{ + for(uint32_t uHalfP = 0; uHalfP < 0xffff; uHalfP += 60) { + unsigned char x[2]; + x[1] = uHalfP & 0xff; + x[0] = uHalfP >> 8; + double d = decode_half(x); + + // Contruct the CBOR for the half-precision float by hand + UsefulBuf_MAKE_STACK_UB(__xx, 3); + UsefulOutBuf UOB; + UsefulOutBuf_Init(&UOB, __xx); + + const uint8_t uHalfPrecInitialByte = HALF_PREC_FLOAT + (CBOR_MAJOR_TYPE_SIMPLE << 5); // 0xf9 + UsefulOutBuf_AppendByte(&UOB, uHalfPrecInitialByte); // The initial byte for a half-precision float + UsefulOutBuf_AppendUint16(&UOB, (uint16_t)uHalfP); + + // Now parse the hand-constructed CBOR. This will invoke the conversion to a float + QCBORDecodeContext DC; + QCBORDecode_Init(&DC, UsefulOutBuf_OutUBuf(&UOB), 0); + + QCBORItem Item; + + QCBORDecode_GetNext(&DC, &Item); + if(Item.uDataType != QCBOR_TYPE_DOUBLE) { + return -1; + } + + //printf("%04x QCBOR:%15.15f RFC: %15.15f (%8x)\n", uHalfP,Item.val.fnum, d , UsefulBufUtil_CopyFloatToUint32(d)); + + if(isnan(d)) { + // The RFC code uses the native instructions which may or may not + // handle sNaN, qNaN and NaN payloads correctly. This test just + // makes sure it is a NaN and doesn't worry about the type of NaN + if(!isnan(Item.val.dfnum)) { + return -3; + } + } else { + if(Item.val.dfnum != d) { + return -2; + } + } + } + return 0; +} + + +/* + {"zero": 0.0, + "negative zero": -0.0, + "infinitity": Infinity, + "negative infinitity": -Infinity, + "NaN": NaN, + "one": 1.0, + "one third": 0.333251953125, + "largest half-precision": 65504.0, + "largest half-precision point one": 65504.1, + "too-large half-precision": 65536.0, + "smallest subnormal": 5.96046448e-8, + "smallest normal": 0.00006103515261202119, + "biggest subnormal": 0.00006103515625, + "subnormal single": 4.00000646641519e-40, + 3: -2.0, + "large single exp": 2.5521177519070385e+38, + "too-large single exp": 5.104235503814077e+38, + "biggest single with prec": 16777216.0, + "first single with prec loss": 16777217.0, + 1: "fin"} + */ +static const uint8_t spExpectedSmallest[] = { + 0xB4, 0x64, 0x7A, 0x65, 0x72, 0x6F, 0xF9, 0x00, 0x00, 0x6D, + 0x6E, 0x65, 0x67, 0x61, 0x74, 0x69, 0x76, 0x65, 0x20, 0x7A, + 0x65, 0x72, 0x6F, 0xF9, 0x80, 0x00, 0x6A, 0x69, 0x6E, 0x66, + 0x69, 0x6E, 0x69, 0x74, 0x69, 0x74, 0x79, 0xF9, 0x7C, 0x00, + 0x73, 0x6E, 0x65, 0x67, 0x61, 0x74, 0x69, 0x76, 0x65, 0x20, + 0x69, 0x6E, 0x66, 0x69, 0x6E, 0x69, 0x74, 0x69, 0x74, 0x79, + 0xF9, 0xFC, 0x00, 0x63, 0x4E, 0x61, 0x4E, 0xF9, 0x7E, 0x00, + 0x63, 0x6F, 0x6E, 0x65, 0xF9, 0x3C, 0x00, 0x69, 0x6F, 0x6E, + 0x65, 0x20, 0x74, 0x68, 0x69, 0x72, 0x64, 0xF9, 0x35, 0x55, + 0x76, 0x6C, 0x61, 0x72, 0x67, 0x65, 0x73, 0x74, 0x20, 0x68, + 0x61, 0x6C, 0x66, 0x2D, 0x70, 0x72, 0x65, 0x63, 0x69, 0x73, + 0x69, 0x6F, 0x6E, 0xF9, 0x7B, 0xFF, 0x78, 0x20, 0x6C, 0x61, + 0x72, 0x67, 0x65, 0x73, 0x74, 0x20, 0x68, 0x61, 0x6C, 0x66, + 0x2D, 0x70, 0x72, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6F, 0x6E, + 0x20, 0x70, 0x6F, 0x69, 0x6E, 0x74, 0x20, 0x6F, 0x6E, 0x65, + 0xFB, 0x40, 0xEF, 0xFC, 0x03, 0x33, 0x33, 0x33, 0x33, 0x78, + 0x18, 0x74, 0x6F, 0x6F, 0x2D, 0x6C, 0x61, 0x72, 0x67, 0x65, + 0x20, 0x68, 0x61, 0x6C, 0x66, 0x2D, 0x70, 0x72, 0x65, 0x63, + 0x69, 0x73, 0x69, 0x6F, 0x6E, 0xFA, 0x47, 0x80, 0x00, 0x00, + 0x72, 0x73, 0x6D, 0x61, 0x6C, 0x6C, 0x65, 0x73, 0x74, 0x20, + 0x73, 0x75, 0x62, 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C, 0xFB, + 0x3E, 0x70, 0x00, 0x00, 0x00, 0x1C, 0x5F, 0x68, 0x6F, 0x73, + 0x6D, 0x61, 0x6C, 0x6C, 0x65, 0x73, 0x74, 0x20, 0x6E, 0x6F, + 0x72, 0x6D, 0x61, 0x6C, 0xFA, 0x38, 0x7F, 0xFF, 0xFF, 0x71, + 0x62, 0x69, 0x67, 0x67, 0x65, 0x73, 0x74, 0x20, 0x73, 0x75, + 0x62, 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C, 0xF9, 0x04, 0x00, + 0x70, 0x73, 0x75, 0x62, 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C, + 0x20, 0x73, 0x69, 0x6E, 0x67, 0x6C, 0x65, 0xFB, 0x37, 0xC1, + 0x6C, 0x28, 0x00, 0x00, 0x00, 0x00, 0x03, 0xF9, 0xC0, 0x00, + 0x70, 0x6C, 0x61, 0x72, 0x67, 0x65, 0x20, 0x73, 0x69, 0x6E, + 0x67, 0x6C, 0x65, 0x20, 0x65, 0x78, 0x70, 0xFA, 0x7F, 0x40, + 0x00, 0x00, 0x74, 0x74, 0x6F, 0x6F, 0x2D, 0x6C, 0x61, 0x72, + 0x67, 0x65, 0x20, 0x73, 0x69, 0x6E, 0x67, 0x6C, 0x65, 0x20, + 0x65, 0x78, 0x70, 0xFB, 0x47, 0xF8, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x78, 0x18, 0x62, 0x69, 0x67, 0x67, 0x65, 0x73, + 0x74, 0x20, 0x73, 0x69, 0x6E, 0x67, 0x6C, 0x65, 0x20, 0x77, + 0x69, 0x74, 0x68, 0x20, 0x70, 0x72, 0x65, 0x63, 0xFA, 0x4B, + 0x80, 0x00, 0x00, 0x78, 0x1B, 0x66, 0x69, 0x72, 0x73, 0x74, + 0x20, 0x73, 0x69, 0x6E, 0x67, 0x6C, 0x65, 0x20, 0x77, 0x69, + 0x74, 0x68, 0x20, 0x70, 0x72, 0x65, 0x63, 0x20, 0x6C, 0x6F, + 0x73, 0x73, 0xFB, 0x41, 0x70, 0x00, 0x00, 0x10, 0x00, 0x00, + 0x00, 0x01, 0x63, 0x66, 0x69, 0x6E +}; + + +int DoubleAsSmallestTest() +{ + UsefulBuf_MAKE_STACK_UB(EncodedHalfsMem, 420); + +#define QCBOREncode_AddDoubleAsSmallestToMap QCBOREncode_AddDoubleToMap +#define QCBOREncode_AddDoubleAsSmallestToMapN QCBOREncode_AddDoubleToMapN + + + QCBOREncodeContext EC; + QCBOREncode_Init(&EC, EncodedHalfsMem); + // These are mostly from https://en.wikipedia.org/wiki/Half-precision_floating-point_format + QCBOREncode_OpenMap(&EC); + // 64 # text(4) + // 7A65726F # "zero" + // F9 0000 # primitive(0) + QCBOREncode_AddDoubleAsSmallestToMap(&EC, "zero", 0.00); + + // 64 # text(4) + // 7A65726F # "negative zero" + // F9 8000 # primitive(0) + QCBOREncode_AddDoubleAsSmallestToMap(&EC, "negative zero", -0.00); + + // 6A # text(10) + // 696E66696E6974697479 # "infinitity" + // F9 7C00 # primitive(31744) + QCBOREncode_AddDoubleAsSmallestToMap(&EC, "infinitity", INFINITY); + + // 73 # text(19) + // 6E6567617469766520696E66696E6974697479 # "negative infinitity" + // F9 FC00 # primitive(64512) + QCBOREncode_AddDoubleAsSmallestToMap(&EC, "negative infinitity", -INFINITY); + + // 63 # text(3) + // 4E614E # "NaN" + // F9 7E00 # primitive(32256) + QCBOREncode_AddDoubleAsSmallestToMap(&EC, "NaN", NAN); + + // TODO: test a few NaN variants + + // 63 # text(3) + // 6F6E65 # "one" + // F9 3C00 # primitive(15360) + QCBOREncode_AddDoubleAsSmallestToMap(&EC, "one", 1.0); + + // 69 # text(9) + // 6F6E65207468697264 # "one third" + // F9 3555 # primitive(13653) + QCBOREncode_AddDoubleAsSmallestToMap(&EC, "one third", 0.333251953125); + + // 76 # text(22) + // 6C6172676573742068616C662D707265636973696F6E # "largest half-precision" + // F9 7BFF # primitive(31743) + QCBOREncode_AddDoubleAsSmallestToMap(&EC, "largest half-precision",65504.0); + + // 76 # text(22) + // 6C6172676573742068616C662D707265636973696F6E # "largest half-precision" + // F9 7BFF # primitive(31743) + QCBOREncode_AddDoubleAsSmallestToMap(&EC, "largest half-precision point one",65504.1); + + // Float 65536.0F is 0x47800000 in hex. It has an exponent of 16, which is larger than 15, the largest half-precision exponent + // 78 18 # text(24) + // 746F6F2D6C617267652068616C662D707265636973696F6E # "too-large half-precision" + // FA 47800000 # primitive(31743) + QCBOREncode_AddDoubleAsSmallestToMap(&EC, "too-large half-precision", 65536.0); + + // The smallest possible half-precision subnormal, but digitis are lost converting + // to half, so this turns into a double + // 72 # text(18) + // 736D616C6C657374207375626E6F726D616C # "smallest subnormal" + // FB 3E700000001C5F68 # primitive(4499096027744984936) + QCBOREncode_AddDoubleAsSmallestToMap(&EC, "smallest subnormal", 0.0000000596046448); + + // The smallest possible half-precision snormal, but digitis are lost converting + // to half, so this turns into a single TODO: confirm this is right + // 6F # text(15) + // 736D616C6C657374206E6F726D616C # "smallest normal" + // FA 387FFFFF # primitive(947912703) + // in hex single is 0x387fffff, exponent -15, significand 7fffff + QCBOREncode_AddDoubleAsSmallestToMap(&EC, "smallest normal", 0.0000610351526F); + + // 71 # text(17) + // 62696767657374207375626E6F726D616C # "biggest subnormal" + // F9 0400 # primitive(1024) + // in hex single is 0x38800000, exponent -14, significand 0 + QCBOREncode_AddDoubleAsSmallestToMap(&EC, "biggest subnormal", 0.0000610351563F); + + // 70 # text(16) + // 7375626E6F726D616C2073696E676C65 # "subnormal single" + // FB 37C16C2800000000 # primitive(4017611261645684736) + QCBOREncode_AddDoubleAsSmallestToMap(&EC, "subnormal single", 4e-40L); + + // 03 # unsigned(3) + // F9 C000 # primitive(49152) + QCBOREncode_AddDoubleAsSmallestToMapN(&EC, 3, -2.0); + + // 70 # text(16) + // 6C617267652073696E676C6520657870 # "large single exp" + // FA 7F400000 # primitive(2134900736) + // (0x01LL << (DOUBLE_NUM_SIGNIFICAND_BITS-1)) | ((127LL + DOUBLE_EXPONENT_BIAS) << DOUBLE_EXPONENT_SHIFT); + QCBOREncode_AddDoubleAsSmallestToMap(&EC, "large single exp", 2.5521177519070385E+38); // Exponent fits single + + // 74 # text(20) + // 746F6F2D6C617267652073696E676C6520657870 # "too-large single exp" + // FB 47F8000000000000 # primitive(5185894970917126144) + // (0x01LL << (DOUBLE_NUM_SIGNIFICAND_BITS-1)) | ((128LL + DOUBLE_EXPONENT_BIAS) << DOUBLE_EXPONENT_SHIFT); + QCBOREncode_AddDoubleAsSmallestToMap(&EC, "too-large single exp", 5.104235503814077E+38); // Exponent too large for single + + // 66 # text(6) + // 646664666465 # "dfdfde" + // FA 4B800000 # primitive(1266679808) + QCBOREncode_AddDoubleAsSmallestToMap(&EC, "biggest single with prec",16777216); // Single with no precision loss + + // 78 18 # text(24) + // 626967676573742073696E676C6520776974682070726563 # "biggest single with prec" + // FA 4B800000 # primitive(1266679808) + QCBOREncode_AddDoubleAsSmallestToMap(&EC, "first single with prec loss",16777217); // Double becuase of precision loss + + // Just a convenient marker when cutting and pasting encoded CBOR + QCBOREncode_AddSZStringToMapN(&EC, 1, "fin"); + + QCBOREncode_CloseMap(&EC); + + UsefulBufC EncodedHalfs; + int nReturn = QCBOREncode_Finish(&EC, &EncodedHalfs); + if(nReturn) { + return -1; + } + + if(UsefulBuf_Compare(EncodedHalfs, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedSmallest))) { + return -3; + } + + return 0; +} + + + +#ifdef NAN_EXPERIMENT +/* + Code for checking what the double to float cast does with + NaNs. Not run as part of tests. Keep it around to + be able to check various platforms and CPUs. + */ + +#define DOUBLE_NUM_SIGNIFICAND_BITS (52) +#define DOUBLE_NUM_EXPONENT_BITS (11) +#define DOUBLE_NUM_SIGN_BITS (1) + +#define DOUBLE_SIGNIFICAND_SHIFT (0) +#define DOUBLE_EXPONENT_SHIFT (DOUBLE_NUM_SIGNIFICAND_BITS) +#define DOUBLE_SIGN_SHIFT (DOUBLE_NUM_SIGNIFICAND_BITS + DOUBLE_NUM_EXPONENT_BITS) + +#define DOUBLE_SIGNIFICAND_MASK (0xfffffffffffffULL) // The lower 52 bits +#define DOUBLE_EXPONENT_MASK (0x7ffULL << DOUBLE_EXPONENT_SHIFT) // 11 bits of exponent +#define DOUBLE_SIGN_MASK (0x01ULL << DOUBLE_SIGN_SHIFT) // 1 bit of sign +#define DOUBLE_QUIET_NAN_BIT (0x01ULL << (DOUBLE_NUM_SIGNIFICAND_BITS-1)) + + +static int NaNExperiments() { + double dqNaN = UsefulBufUtil_CopyUint64ToDouble(DOUBLE_EXPONENT_MASK | DOUBLE_QUIET_NAN_BIT); + double dsNaN = UsefulBufUtil_CopyUint64ToDouble(DOUBLE_EXPONENT_MASK | 0x01); + double dqNaNPayload = UsefulBufUtil_CopyUint64ToDouble(DOUBLE_EXPONENT_MASK | DOUBLE_QUIET_NAN_BIT | 0xf00f); + + float f1 = (float)dqNaN; + float f2 = (float)dsNaN; + float f3 = (float)dqNaNPayload; + + + uint32_t uqNaN = UsefulBufUtil_CopyFloatToUint32((float)dqNaN); + uint32_t usNaN = UsefulBufUtil_CopyFloatToUint32((float)dsNaN); + uint32_t uqNaNPayload = UsefulBufUtil_CopyFloatToUint32((float)dqNaNPayload); + + // Result of this on x86 is that every NaN is a qNaN. The intel + // CVTSD2SS instruction ignores the NaN payload and even converts + // a sNaN to a qNaN. + + return 0; +} +#endif + + + diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/qcbor/test/float_tests.h b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/qcbor/test/float_tests.h new file mode 100644 index 0000000..b7174c8 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/qcbor/test/float_tests.h @@ -0,0 +1,23 @@ +/*============================================================================== + float_tests.h -- tests for float and conversion to/from half-precision + + Copyright (c) 2018-2019, Laurence Lundblade. All rights reserved. + + SPDX-License-Identifier: BSD-3-Clause + + See BSD-3-Clause license in README.md + + Created on 9/19/18 + ==============================================================================*/ + +#ifndef float_tests_h +#define float_tests_h + +int HalfPrecisionDecodeBasicTests(void); + +int DoubleAsSmallestTest(void); + +int HalfPrecisionAgainstRFCCodeTest(void); + + +#endif /* float_tests_h */ diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/qcbor/test/half_to_double_from_rfc7049.c b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/qcbor/test/half_to_double_from_rfc7049.c new file mode 100644 index 0000000..4d8fb67 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/qcbor/test/half_to_double_from_rfc7049.c @@ -0,0 +1,46 @@ +/* + SPDX-License-Identifier: BSD-2-Clause + + Copyright (c) 2013 IETF Trust and the persons identified as the + document authors. All rights reserved. + + This document is subject to BCP 78 and the IETF Trust's Legal + Provisions Relating to IETF Documents + (http://trustee.ietf.org/license-info) in effect on the date of + publication of this document. Please review these documents + carefully, as they describe your rights and restrictions with respect + to this document. Code Components extracted from this document must + include Simplified BSD License text as described in Section 4.e of + the Trust Legal Provisions and are provided without warranty as + described in the Simplified BSD License. + + */ + +/* + This code is from RFC 7049. It is not used in the main implementation + because: + a) it adds a dependency on and ldexp(). + b) the license may be an issue + + QCBOR does support half-precision, but rather than using + floating point math like this, it does it with bit shifting + and masking. + + This code is here to test that code. + + */ + +#include "half_to_double_from_rfc7049.h" + +#include + +double decode_half(unsigned char *halfp) { + int half = (halfp[0] << 8) + halfp[1]; + int exp = (half >> 10) & 0x1f; + int mant = half & 0x3ff; + double val; + if (exp == 0) val = ldexp(mant, -24); + else if (exp != 31) val = ldexp(mant + 1024, exp - 25); + else val = mant == 0 ? INFINITY : NAN; + return half & 0x8000 ? -val : val; +} diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/qcbor/test/half_to_double_from_rfc7049.h b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/qcbor/test/half_to_double_from_rfc7049.h new file mode 100644 index 0000000..9f69e35 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/qcbor/test/half_to_double_from_rfc7049.h @@ -0,0 +1,18 @@ +/*============================================================================== + half_to_double_from_rfc7049.h -- interface to IETF float conversion code. + + Copyright (c) 2018-2019, Laurence Lundblade. All rights reserved. + + SPDX-License-Identifier: BSD-3-Clause + + See BSD-3-Clause license in README.md + + Created on 9/23/18 + ==============================================================================*/ + +#ifndef half_to_double_from_rfc7049_h +#define half_to_double_from_rfc7049_h + +double decode_half(unsigned char *halfp); + +#endif /* half_to_double_from_rfc7049_h */ diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/qcbor/test/qcbor_decode_tests.c b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/qcbor/test/qcbor_decode_tests.c new file mode 100644 index 0000000..9ffc3a0 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/qcbor/test/qcbor_decode_tests.c @@ -0,0 +1,2837 @@ +/*============================================================================== + Copyright (c) 2016-2018, The Linux Foundation. + Copyright (c) 2018-2019, Laurence Lundblade. + All rights reserved. + SPDX-License-Identifier: BSD-3-Clause + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of The Linux Foundation nor the names of its + contributors, nor the name "Laurence Lundblade" may be used to + endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ==============================================================================*/ + +#include "qcbor_decode_tests.h" +#include "qcbor.h" +#include +#include // for fabs() + + +#ifdef PRINT_FUNCTIONS_FOR_DEBUGGING +#include + +static void PrintUsefulBufC(const char *szLabel, UsefulBufC Buf) +{ + if(szLabel) { + printf("%s ", szLabel); + } + + size_t i; + for(i = 0; i < Buf.len; i++) { + uint8_t Z = ((uint8_t *)Buf.ptr)[i]; + printf("%02x ", Z); + } + printf("\n"); + + fflush(stdout); +} + +/*static void printencoded(const char *szLabel, const uint8_t *pEncoded, size_t nLen) +{ + PrintUsefulBufC(szLabel, (UsefulBufC){pEncoded, nLen}); +}*/ +#endif + + +static const uint8_t spExpectedEncodedInts[] = { + 0x98, 0x2f, 0x3b, 0x7f, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x3b, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x3a, 0xff, 0xff, 0xff, + 0xff, 0x3a, 0xff, 0xff, 0xff, 0xfe, 0x3a, 0xff, + 0xff, 0xff, 0xfd, 0x3a, 0x7f, 0xff, 0xff, 0xff, + 0x3a, 0x7f, 0xff, 0xff, 0xfe, 0x3a, 0x00, 0x01, + 0x00, 0x01, 0x3a, 0x00, 0x01, 0x00, 0x00, 0x39, + 0xff, 0xff, 0x39, 0xff, 0xfe, 0x39, 0xff, 0xfd, + 0x39, 0x01, 0x00, 0x38, 0xff, 0x38, 0xfe, 0x38, + 0xfd, 0x38, 0x18, 0x37, 0x36, 0x20, 0x00, 0x00, + 0x01, 0x16, 0x17, 0x18, 0x18, 0x18, 0x19, 0x18, + 0x1a, 0x18, 0xfe, 0x18, 0xff, 0x19, 0x01, 0x00, + 0x19, 0x01, 0x01, 0x19, 0xff, 0xfe, 0x19, 0xff, + 0xff, 0x1a, 0x00, 0x01, 0x00, 0x00, 0x1a, 0x00, + 0x01, 0x00, 0x01, 0x1a, 0x00, 0x01, 0x00, 0x02, + 0x1a, 0x7f, 0xff, 0xff, 0xff, 0x1a, 0x7f, 0xff, + 0xff, 0xff, 0x1a, 0x80, 0x00, 0x00, 0x00, 0x1a, + 0x80, 0x00, 0x00, 0x01, 0x1a, 0xff, 0xff, 0xff, + 0xfe, 0x1a, 0xff, 0xff, 0xff, 0xff, 0x1b, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x1b, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, + 0x1b, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x1b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff}; + + +// return CBOR error or -1 if type of value doesn't match + +static int IntegerValuesParseTestInternal(QCBORDecodeContext *pDCtx) +{ + QCBORItem Item; + int nCBORError; + + if((nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) + return nCBORError; + if(Item.uDataType != QCBOR_TYPE_ARRAY) + return -1; + + if((nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) + return nCBORError; + if(Item.uDataType != QCBOR_TYPE_INT64 || // Todo; fix this for 32-bit machines + Item.val.int64 != -9223372036854775807LL - 1) + return -1; + + if((nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) + return nCBORError; + if(Item.uDataType != QCBOR_TYPE_INT64 || + Item.val.int64 != -4294967297) + return -1; + + if((nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) + return nCBORError; + if(Item.uDataType != QCBOR_TYPE_INT64 || + Item.val.int64 != -4294967296) + return -1; + + if((nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) + return nCBORError; + if(Item.uDataType != QCBOR_TYPE_INT64 || + Item.val.int64 != -4294967295) + return -1; + + if((nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) + return nCBORError; + if(Item.uDataType != QCBOR_TYPE_INT64 || + Item.val.int64 != -4294967294) + return -1; + + + if((nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) + return nCBORError; + if(Item.uDataType != QCBOR_TYPE_INT64 || + Item.val.int64 != -2147483648) + return -1; + + if((nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) + return nCBORError; + if(Item.uDataType != QCBOR_TYPE_INT64 || + Item.val.int64 != -2147483647) + return -1; + + if((nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) + return nCBORError; + if(Item.uDataType != QCBOR_TYPE_INT64 || + Item.val.int64 != -65538) + return -1; + + if((nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) + return nCBORError; + if(Item.uDataType != QCBOR_TYPE_INT64 || + Item.val.int64 != -65537) + return -1; + + if((nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) + return nCBORError; + if(Item.uDataType != QCBOR_TYPE_INT64 || + Item.val.int64 != -65536) + return -1; + + + if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) + return nCBORError; + if(Item.uDataType != QCBOR_TYPE_INT64 || + Item.val.int64 != -65535) + return -1; + + + if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) + return nCBORError; + if(Item.uDataType != QCBOR_TYPE_INT64 || + Item.val.int64 != -65534) + return -1; + + + if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) + return nCBORError; + if(Item.uDataType != QCBOR_TYPE_INT64 || + Item.val.int64 != -257) + return -1; + + if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) + return nCBORError; + if(Item.uDataType != QCBOR_TYPE_INT64 || + Item.val.int64 != -256) + return -1; + + if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) + return nCBORError; + if(Item.uDataType != QCBOR_TYPE_INT64 || + Item.val.int64 != -255) + return -1; + + if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) + return nCBORError; + if(Item.uDataType != QCBOR_TYPE_INT64 || + Item.val.int64 != -254) + return -1; + + + if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) + return nCBORError; + if(Item.uDataType != QCBOR_TYPE_INT64 || + Item.val.int64 != -25) + return -1; + + + if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) + return nCBORError; + if(Item.uDataType != QCBOR_TYPE_INT64 || + Item.val.int64 != -24) + return -1; + + + if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) + return nCBORError; + if(Item.uDataType != QCBOR_TYPE_INT64 || + Item.val.int64 != -23) + return -1; + + + if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) + return nCBORError; + if(Item.uDataType != QCBOR_TYPE_INT64 || + Item.val.int64 != -1) + return -1; + + + if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) + return nCBORError; + if(Item.uDataType != QCBOR_TYPE_INT64 || + Item.val.int64 != 0) + return -1; + + + if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) + return nCBORError; + if(Item.uDataType != QCBOR_TYPE_INT64 || + Item.val.int64 != 0) + return -1; + + if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) + return nCBORError; + if(Item.uDataType != QCBOR_TYPE_INT64 || + Item.val.int64 != 1) + return -1; + + + if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) + return nCBORError; + if(Item.uDataType != QCBOR_TYPE_INT64 || + Item.val.int64 != 22) + return -1; + + + if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) + return nCBORError; + if(Item.uDataType != QCBOR_TYPE_INT64 || + Item.val.int64 != 23) + return -1; + + + if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) + return nCBORError; + if(Item.uDataType != QCBOR_TYPE_INT64 || + Item.val.int64 != 24) + return -1; + + + if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) + return nCBORError; + if(Item.uDataType != QCBOR_TYPE_INT64 || + Item.val.int64 != 25) + return -1; + + if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) + return nCBORError; + if(Item.uDataType != QCBOR_TYPE_INT64 || + Item.val.int64 != 26) + return -1; + + + if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) + return nCBORError; + if(Item.uDataType != QCBOR_TYPE_INT64 || + Item.val.int64 != 254) + return -1; + + + if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) + return nCBORError; + if(Item.uDataType != QCBOR_TYPE_INT64 || + Item.val.int64 != 255) + return -1; + + + if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) + return nCBORError; + if(Item.uDataType != QCBOR_TYPE_INT64 || + Item.val.int64 != 256) + return -1; + + + if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) + return nCBORError; + if(Item.uDataType != QCBOR_TYPE_INT64 || + Item.val.int64 != 257) + return -1; + + if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) + return nCBORError; + if(Item.uDataType != QCBOR_TYPE_INT64 || + Item.val.int64 != 65534) + return -1; + + + if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) + return nCBORError; + if(Item.uDataType != QCBOR_TYPE_INT64 || + Item.val.int64 != 65535) + return -1; + + + if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) + return nCBORError; + if(Item.uDataType != QCBOR_TYPE_INT64 || + Item.val.int64 != 65536) + return -1; + + if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) + return nCBORError; + if(Item.uDataType != QCBOR_TYPE_INT64 || + Item.val.int64 != 65537) + return -1; + + if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) + return nCBORError; + if(Item.uDataType != QCBOR_TYPE_INT64 || + Item.val.int64 != 65538) + return -1; + + if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) + return nCBORError; + if(Item.uDataType != QCBOR_TYPE_INT64 || + Item.val.int64 != 2147483647) + return -1; + + if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) + return nCBORError; + if(Item.uDataType != QCBOR_TYPE_INT64 || + Item.val.int64 != 2147483647) + return -1; + + if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) + return nCBORError; + if(Item.uDataType != QCBOR_TYPE_INT64 || + Item.val.int64 != 2147483648) + return -1; + + if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) + return nCBORError; + if(Item.uDataType != QCBOR_TYPE_INT64 || + Item.val.int64 != 2147483649) + return -1; + + if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) + return nCBORError; + if(Item.uDataType != QCBOR_TYPE_INT64 || + Item.val.int64 != 4294967294) + return -1; + + + if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) + return nCBORError; + if(Item.uDataType != QCBOR_TYPE_INT64 || + Item.val.int64 != 4294967295) + return -1; + + + if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) + return nCBORError; + if(Item.uDataType != QCBOR_TYPE_INT64 || + Item.val.int64 != 4294967296) + return -1; + + + if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) + return nCBORError; + if(Item.uDataType != QCBOR_TYPE_INT64 || + Item.val.int64 != 4294967297) + return -1; + + + + if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) + return nCBORError; + if(Item.uDataType != QCBOR_TYPE_INT64 || + Item.val.int64 != 9223372036854775807LL) + return -1; + + + if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) + return nCBORError; + if(Item.uDataType != QCBOR_TYPE_UINT64 || + Item.val.uint64 != 18446744073709551615ULL) + return -1; + + + if(QCBORDecode_Finish(pDCtx) != QCBOR_SUCCESS) { + return -1; + } + + return 0; +} + + +/* + Tests the decoding of lots of different integers sizes + and values. + */ + +int IntegerValuesParseTest() +{ + int n; + QCBORDecodeContext DCtx; + + QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedEncodedInts), QCBOR_DECODE_MODE_NORMAL); + + n = IntegerValuesParseTestInternal(&DCtx); + + return(n); +} + + +/* + Creates a simple CBOR array and returns it in *pEncoded. The array is malloced + and needs to be freed. This is used by several tests. + + Two of the inputs can be set. Two other items in the array are fixed. + + */ + +static uint8_t spSimpleArrayBuffer[50]; + +static int CreateSimpleArray(int nInt1, int nInt2, uint8_t **pEncoded, size_t *pEncodedLen) +{ + QCBOREncodeContext ECtx; + int nReturn = -1; + + *pEncoded = NULL; + *pEncodedLen = INT32_MAX; + + // loop runs CBOR encoding twice. First with no buffer to + // calculate the length so buffer can be allocated correctly, + // and last with the buffer to do the actual encoding + do { + QCBOREncode_Init(&ECtx, (UsefulBuf){*pEncoded, *pEncodedLen}); + QCBOREncode_OpenArray(&ECtx); + QCBOREncode_AddInt64(&ECtx, nInt1); + QCBOREncode_AddInt64(&ECtx, nInt2); + QCBOREncode_AddBytes(&ECtx, ((UsefulBufC) {"galactic", 8})); + QCBOREncode_AddBytes(&ECtx, ((UsefulBufC) {"haven token", 11})); + QCBOREncode_CloseArray(&ECtx); + + if(QCBOREncode_FinishGetSize(&ECtx, pEncodedLen)) + goto Done; + + if(*pEncoded != NULL) { + nReturn = 0; + goto Done; + } + + // Use static buffer to avoid dependency on malloc() + if(*pEncodedLen > sizeof(spSimpleArrayBuffer)) { + goto Done; + } + *pEncoded = spSimpleArrayBuffer; + + } while(1); + +Done: + return nReturn; +} + + +/* + {"first integer": 42, + "an array of two strings": [ + "string1", "string2" + ], + "map in a map": { + "bytes 1": h'78787878', + "bytes 2": h'79797979', + "another int": 98, + "text 2": "lies, damn lies and statistics" + } + } + */ + +static uint8_t pValidMapEncoded[] = { + 0xa3, 0x6d, 0x66, 0x69, 0x72, 0x73, 0x74, 0x20, 0x69, 0x6e, + 0x74, 0x65, 0x67, 0x65, 0x72, 0x18, 0x2a, 0x77, 0x61, 0x6e, + 0x20, 0x61, 0x72, 0x72, 0x61, 0x79, 0x20, 0x6f, 0x66, 0x20, + 0x74, 0x77, 0x6f, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, + 0x73, 0x82, 0x67, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x31, + 0x67, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x32, 0x6c, 0x6d, + 0x61, 0x70, 0x20, 0x69, 0x6e, 0x20, 0x61, 0x20, 0x6d, 0x61, + 0x70, 0xa4, 0x67, 0x62, 0x79, 0x74, 0x65, 0x73, 0x20, 0x31, + 0x44, 0x78, 0x78, 0x78, 0x78, 0x67, 0x62, 0x79, 0x74, 0x65, + 0x73, 0x20, 0x32, 0x44, 0x79, 0x79, 0x79, 0x79, 0x6b, 0x61, + 0x6e, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x20, 0x69, 0x6e, 0x74, + 0x18, 0x62, 0x66, 0x74, 0x65, 0x78, 0x74, 0x20, 0x32, 0x78, + 0x1e, 0x6c, 0x69, 0x65, 0x73, 0x2c, 0x20, 0x64, 0x61, 0x6d, + 0x6e, 0x20, 0x6c, 0x69, 0x65, 0x73, 0x20, 0x61, 0x6e, 0x64, + 0x20, 0x73, 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, + 0x73 } ; + +static int ParseOrderedArray(const uint8_t *pEncoded, size_t nLen, int64_t *pInt1, int64_t *pInt2, const uint8_t **pBuf3, size_t *pBuf3Len, const uint8_t **pBuf4, size_t *pBuf4Len) +{ + QCBORDecodeContext DCtx; + QCBORItem Item; + int nReturn = -1; // assume error until success + + QCBORDecode_Init(&DCtx, (UsefulBufC){pEncoded, nLen}, QCBOR_DECODE_MODE_NORMAL); + + // Make sure the first thing is a map + if(QCBORDecode_GetNext(&DCtx, &Item) != 0 || Item.uDataType != QCBOR_TYPE_ARRAY) + goto Done; + + // First integer + if(QCBORDecode_GetNext(&DCtx, &Item) != 0 || Item.uDataType != QCBOR_TYPE_INT64) + goto Done; + *pInt1 = Item.val.int64; + + // Second integer + if(QCBORDecode_GetNext(&DCtx, &Item) != 0 || Item.uDataType != QCBOR_TYPE_INT64) + goto Done; + *pInt2 = Item.val.int64; + + // First string + if(QCBORDecode_GetNext(&DCtx, &Item) != 0 || Item.uDataType != QCBOR_TYPE_BYTE_STRING) + goto Done; + *pBuf3 = Item.val.string.ptr; + *pBuf3Len = Item.val.string.len; + + // Second string + if(QCBORDecode_GetNext(&DCtx, &Item) != 0 || Item.uDataType != QCBOR_TYPE_BYTE_STRING) + goto Done; + *pBuf4 = Item.val.string.ptr; + *pBuf4Len = Item.val.string.len; + + nReturn = 0; + +Done: + return(nReturn); +} + + + + +int SimpleArrayTest() +{ + uint8_t *pEncoded; + size_t nEncodedLen; + + int64_t i1=0, i2=0; + size_t i3=0, i4=0; + const uint8_t *s3= (uint8_t *)""; + const uint8_t *s4= (uint8_t *)""; + + + if(CreateSimpleArray(23, 6000, &pEncoded, &nEncodedLen) < 0) { + return(-1); + } + + ParseOrderedArray(pEncoded, nEncodedLen, &i1, &i2, &s3, &i3, &s4, &i4); + + if(i1 != 23 || + i2 != 6000 || + i3 != 8 || + i4 != 11 || + memcmp("galactic", s3, 8) !=0 || + memcmp("haven token", s4, 11) !=0) { + return(-1); + } + + return(0); +} + + + +static uint8_t spDeepArrays[] = {0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x80}; + +int ParseDeepArrayTest() +{ + QCBORDecodeContext DCtx; + int nReturn = 0; + int i; + + QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spDeepArrays), QCBOR_DECODE_MODE_NORMAL); + + for(i = 0; i < 10; i++) { + QCBORItem Item; + + if(QCBORDecode_GetNext(&DCtx, &Item) != 0 || + Item.uDataType != QCBOR_TYPE_ARRAY || + Item.uNestingLevel != i) { + nReturn = -1; + break; + } + } + + return(nReturn); +} + +// Big enough to test nesting to the depth of 24 +static uint8_t spTooDeepArrays[] = {0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x80}; + +int ParseTooDeepArrayTest() +{ + QCBORDecodeContext DCtx; + int nReturn = 0; + int i; + QCBORItem Item; + + + QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spTooDeepArrays), QCBOR_DECODE_MODE_NORMAL); + + for(i = 0; i < QCBOR_MAX_ARRAY_NESTING1; i++) { + + if(QCBORDecode_GetNext(&DCtx, &Item) != 0 || + Item.uDataType != QCBOR_TYPE_ARRAY || + Item.uNestingLevel != i) { + nReturn = -1; + break; + } + } + + if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_ARRAY_NESTING_TOO_DEEP) + nReturn = -1; + + return(nReturn); +} + + + + +int ShortBufferParseTest() +{ + int nResult = 0; + QCBORDecodeContext DCtx; + int num; + + for(num = sizeof(spExpectedEncodedInts)-1; num; num--) { + int n; + + QCBORDecode_Init(&DCtx, (UsefulBufC){spExpectedEncodedInts, num}, QCBOR_DECODE_MODE_NORMAL); + + n = IntegerValuesParseTestInternal(&DCtx); + + //printf("Len %d, result: %d\n", num, n); + + if(n != QCBOR_ERR_HIT_END) { + nResult = -1; + goto Done; + } + } +Done: + return nResult; +} + + + +int ShortBufferParseTest2() +{ + uint8_t *pEncoded; + int nReturn; + size_t nEncodedLen; + + int64_t i1, i2; + size_t i3, i4; + const uint8_t *s3, *s4; + + nReturn = 0; + + if(CreateSimpleArray(23, 6000, &pEncoded, &nEncodedLen) < 0) { + return(-1); + } + + for(nEncodedLen--; nEncodedLen; nEncodedLen--) { + int nResult = ParseOrderedArray(pEncoded, (uint32_t)nEncodedLen, &i1, &i2, &s3, &i3, &s4, &i4); + if(nResult == 0) { + nReturn = -1; + } + } + + return(nReturn); +} + +/* + Decode and thoroughly check a moderately complex + set of maps + */ +static int ParseMapTest1(QCBORDecodeMode nMode) +{ + QCBORDecodeContext DCtx; + QCBORItem Item; + int nCBORError; + + QCBORDecode_Init(&DCtx, (UsefulBufC){pValidMapEncoded, sizeof(pValidMapEncoded)}, nMode); + + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return nCBORError; + } + if(Item.uDataType != QCBOR_TYPE_MAP || + Item.val.uCount != 3) + return -1; + + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return nCBORError; + } + if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || + Item.uDataType != QCBOR_TYPE_INT64 || + Item.val.int64 != 42 || + Item.uDataAlloc || + Item.uLabelAlloc || + UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("first integer"))) { + return -1; + } + + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return nCBORError; + } + if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || + Item.uDataAlloc || + Item.uLabelAlloc || + UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("an array of two strings")) || + Item.uDataType != QCBOR_TYPE_ARRAY || + Item.val.uCount != 2) + return -1; + + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return nCBORError; + } + if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || + Item.uDataAlloc || + Item.uLabelAlloc || + UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("string1"))) { + return -1; + } + + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return nCBORError; + } + if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || + Item.uDataAlloc || + Item.uLabelAlloc || + UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("string2"))) { + return -1; + } + + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return nCBORError; + } + if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || + Item.uDataAlloc || + Item.uLabelAlloc || + UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("map in a map")) || + Item.uDataType != QCBOR_TYPE_MAP || + Item.val.uCount != 4) { + return -1; + } + + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return nCBORError; + } + if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || + UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("bytes 1"))|| + Item.uDataType != QCBOR_TYPE_BYTE_STRING || + Item.uDataAlloc || + Item.uLabelAlloc || + UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("xxxx"))) { + return -1; + } + + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return nCBORError; + } + if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || + UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("bytes 2")) || + Item.uDataType != QCBOR_TYPE_BYTE_STRING || + Item.uDataAlloc || + Item.uLabelAlloc || + UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("yyyy"))) { + return -1; + } + + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return nCBORError; + } + if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || + Item.uDataAlloc || + Item.uLabelAlloc || + UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("another int")) || + Item.uDataType != QCBOR_TYPE_INT64 || + Item.val.int64 != 98) + return -1; + + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return nCBORError; + } + if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || + UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("text 2"))|| + Item.uDataType != QCBOR_TYPE_TEXT_STRING || + Item.uDataAlloc || + Item.uLabelAlloc || + UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("lies, damn lies and statistics"))) { + return -1; + } + + return 0; +} + + +/* + Decode and thoroughly check a moderately complex + set of maps + */ +int ParseMapAsArrayTest() +{ + QCBORDecodeContext DCtx; + QCBORItem Item; + int nCBORError; + + QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded), QCBOR_DECODE_MODE_MAP_AS_ARRAY); + + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return nCBORError; + } + if(Item.uDataType != QCBOR_TYPE_MAP_AS_ARRAY || + Item.val.uCount != 6) { + return -1; + } + + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return nCBORError; + } + if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || + Item.uDataAlloc || + Item.uLabelAlloc || + Item.uLabelType != QCBOR_TYPE_NONE || + UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("first integer"))) { + return -2; + } + + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return nCBORError; + } + if(Item.uLabelType != QCBOR_TYPE_NONE || + Item.uDataType != QCBOR_TYPE_INT64 || + Item.val.int64 != 42 || + Item.uDataAlloc || + Item.uLabelAlloc) { + return -3; + } + + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return nCBORError; + } + if(Item.uLabelType != QCBOR_TYPE_NONE || + Item.uDataAlloc || + Item.uLabelAlloc || + UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("an array of two strings")) || + Item.uDataType != QCBOR_TYPE_TEXT_STRING) { + return -4; + } + + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return nCBORError; + } + if(Item.uLabelType != QCBOR_TYPE_NONE || + Item.uDataAlloc || + Item.uLabelAlloc || + Item.uDataType != QCBOR_TYPE_ARRAY || + Item.val.uCount != 2) { + return -5; + } + + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return nCBORError; + } + if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || + Item.val.string.len != 7 || + Item.uDataAlloc || + Item.uLabelAlloc || + UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("string1"))) { + return -6; + } + + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return nCBORError; + } + if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || + Item.uDataAlloc || + Item.uLabelAlloc || + UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("string2"))) { + return -7; + } + + + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return nCBORError; + } + if(Item.uLabelType != QCBOR_TYPE_NONE || + Item.uDataAlloc || + Item.uLabelAlloc || + UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("map in a map"))) { + return -8; + } + + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return nCBORError; + } + if(Item.uLabelType != QCBOR_TYPE_NONE || + Item.uDataAlloc || + Item.uLabelAlloc || + Item.uDataType != QCBOR_TYPE_MAP_AS_ARRAY || + Item.val.uCount != 8) { + return -9; + } + + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return nCBORError; + } + if(Item.uLabelType != QCBOR_TYPE_NONE || + UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("bytes 1"))|| + Item.uDataType != QCBOR_TYPE_TEXT_STRING || + Item.uDataAlloc || + Item.uLabelAlloc) { + return -10; + } + + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return nCBORError; + } + if(Item.uLabelType != QCBOR_TYPE_NONE || + Item.uDataType != QCBOR_TYPE_BYTE_STRING || + Item.uDataAlloc || + Item.uLabelAlloc || + UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("xxxx"))) { + return -11; + } + + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return nCBORError; + } + if(Item.uLabelType != QCBOR_TYPE_NONE || + UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("bytes 2")) || + Item.uDataType != QCBOR_TYPE_TEXT_STRING || + Item.uDataAlloc || + Item.uLabelAlloc) { + return -12; + } + + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return nCBORError; + } + if(Item.uLabelType != QCBOR_TYPE_NONE || + Item.uDataType != QCBOR_TYPE_BYTE_STRING || + Item.uDataAlloc || + Item.uLabelAlloc || + UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("yyyy"))) { + return -13; + } + + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return nCBORError; + } + if(Item.uLabelType != QCBOR_TYPE_NONE || + Item.uDataAlloc || + Item.uLabelAlloc || + UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("another int")) || + Item.uDataType != QCBOR_TYPE_TEXT_STRING) { + return -14; + } + + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return nCBORError; + } + if(Item.uLabelType != QCBOR_TYPE_NONE || + Item.uDataAlloc || + Item.uLabelAlloc || + Item.uDataType != QCBOR_TYPE_INT64 || + Item.val.int64 != 98) { + return -15; + } + + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return nCBORError; + } + if(Item.uLabelType != QCBOR_TYPE_NONE || + UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("text 2"))|| + Item.uDataType != QCBOR_TYPE_TEXT_STRING || + Item.uDataAlloc || + Item.uLabelAlloc) { + return -16; + } + + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return nCBORError; + } + if(Item.uLabelType != QCBOR_TYPE_NONE || + Item.uDataType != QCBOR_TYPE_TEXT_STRING || + Item.uDataAlloc || + Item.uLabelAlloc || + UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("lies, damn lies and statistics"))) { + return -17; + } + + return 0; +} + + +/* + Fully or partially decode pValidMapEncoded. When + partially decoding check for the right error code. + How much partial decoding depends on nLevel. + + The partial decodes test error conditions of + incomplete encoded input. + + This could be combined with the above test + and made prettier and maybe a little more + thorough. + */ +static int ExtraBytesTest(int nLevel) +{ + QCBORDecodeContext DCtx; + QCBORItem Item; + int nCBORError; + + QCBORDecode_Init(&DCtx, (UsefulBufC){pValidMapEncoded, sizeof(pValidMapEncoded)}, QCBOR_DECODE_MODE_NORMAL); + + if(nLevel < 1) { + if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_EXTRA_BYTES) { + return -1; + } else { + return 0; + } + } + + + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return nCBORError; + } + if(Item.uDataType != QCBOR_TYPE_MAP || + Item.val.uCount != 3) + return -1; + + if(nLevel < 2) { + if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN) { + return -1; + } else { + return 0; + } + } + + + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return nCBORError; + } + if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || + Item.uDataType != QCBOR_TYPE_INT64 || + Item.val.uCount != 42 || + UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("first integer"))) { + return -1; + } + + if(nLevel < 3) { + if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN) { + return -1; + } else { + return 0; + } + } + + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return nCBORError; + } + if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || + UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("an array of two strings")) || + Item.uDataType != QCBOR_TYPE_ARRAY || + Item.val.uCount != 2) { + return -1; + } + + + if(nLevel < 4) { + if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN) { + return -1; + } else { + return 0; + } + } + + + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return nCBORError; + } + if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || + UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("string1"))) { + return -1; + } + + if(nLevel < 5) { + if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN) { + return -1; + } else { + return 0; + } + } + + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return nCBORError; + } + if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || + UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("string2"))) { + return -1; + } + + if(nLevel < 6) { + if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN) { + return -1; + } else { + return 0; + } + } + + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return nCBORError; + } + if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || + UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("map in a map")) || + Item.uDataType != QCBOR_TYPE_MAP || + Item.val.uCount != 4) + return -1; + + if(nLevel < 7) { + if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN) { + return -1; + } else { + return 0; + } + } + + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return nCBORError; + } + if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || + UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("bytes 1")) || + Item.uDataType != QCBOR_TYPE_BYTE_STRING || + UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("xxxx"))) { + return -1; + } + + if(nLevel < 8) { + if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN) { + return -1; + } else { + return 0; + } + } + + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return nCBORError; + } + if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || + UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("bytes 2")) || + Item.uDataType != QCBOR_TYPE_BYTE_STRING || + UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("yyyy"))) { + return -1; + } + + if(nLevel < 9) { + if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN) { + return -1; + } else { + return 0; + } + } + + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return nCBORError; + } + if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || + UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("another int")) || + Item.uDataType != QCBOR_TYPE_INT64 || + Item.val.int64 != 98) + return -1; + + if(nLevel < 10) { + if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN) { + return -1; + } else { + return 0; + } + } + + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { + return nCBORError; + } + if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || + UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("text 2"))|| + Item.uDataType != QCBOR_TYPE_TEXT_STRING || + UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("lies, damn lies and statistics"))) { + return -1; + } + + if(QCBORDecode_Finish(&DCtx)) { + return -1; + } + + return 0; +} + + + + +int ParseMapTest() +{ + // Parse a moderatly complex map structure very thoroughl + int n = ParseMapTest1(QCBOR_DECODE_MODE_NORMAL); + + n = ParseMapTest1(QCBOR_DECODE_MODE_MAP_STRINGS_ONLY); + + if(!n) { + for(int i = 0; i < 10; i++) { + n = ExtraBytesTest(i); + if(n) { + break; + } + } + } + + return(n); +} + + +static uint8_t spSimpleValues[] = {0x8a, 0xf4, 0xf5, 0xf6, 0xf7, 0xff, 0xe0, 0xf3, 0xf8, 0x00, 0xf8, 0x13, 0xf8, 0x1f, 0xf8, 0x20, 0xf8, 0xff}; + +int ParseSimpleTest() +{ + QCBORDecodeContext DCtx; + QCBORItem Item; + int nCBORError; + + + QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spSimpleValues), QCBOR_DECODE_MODE_NORMAL); + + + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) + return nCBORError; + if(Item.uDataType != QCBOR_TYPE_ARRAY || + Item.val.uCount != 10) + return -1; + + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) + return nCBORError; + if(Item.uDataType != QCBOR_TYPE_FALSE) + return -1; + + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) + return nCBORError; + if(Item.uDataType != QCBOR_TYPE_TRUE) + return -1; + + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) + return nCBORError; + if(Item.uDataType != QCBOR_TYPE_NULL) + return -1; + + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) + return nCBORError; + if(Item.uDataType != QCBOR_TYPE_UNDEF) + return -1; + + // A break + if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_BAD_BREAK) + return -1; + + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) + return nCBORError; + if(Item.uDataType != QCBOR_TYPE_UKNOWN_SIMPLE || Item.val.uSimple != 0) + return -1; + + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) + return nCBORError; + if(Item.uDataType != QCBOR_TYPE_UKNOWN_SIMPLE || Item.val.uSimple != 19) + return -1; + + if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_INVALID_CBOR) + return -1; + + if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_INVALID_CBOR) + return -1; + + if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_INVALID_CBOR) + return -1; + + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) + return nCBORError; + if(Item.uDataType != QCBOR_TYPE_UKNOWN_SIMPLE || Item.val.uSimple != 32) + return -1; + + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) + return nCBORError; + if(Item.uDataType != QCBOR_TYPE_UKNOWN_SIMPLE || Item.val.uSimple != 255) + return -1; + + return 0; + +} + + +struct FailInput { + UsefulBufC Input; + int nError; +}; + + +struct FailInput Failures[] = { + { {(uint8_t[]){0x18}, 1}, QCBOR_ERR_HIT_END }, // 1 byte integer missing the byte + { {(uint8_t[]){0x1c}, 1}, QCBOR_ERR_UNSUPPORTED }, // Reserved additional info = 28 + { {(uint8_t[]){0x1d}, 1}, QCBOR_ERR_UNSUPPORTED }, // Reserved additional info = 29 + { {(uint8_t[]){0x1e}, 1}, QCBOR_ERR_UNSUPPORTED }, // Reserved additional info = 30 + { {(uint8_t[]){0x1f}, 1}, QCBOR_ERR_UNSUPPORTED }, // Indefinite length integer + { {(uint8_t[]){0x3c}, 1}, QCBOR_ERR_UNSUPPORTED }, // 1 byte integer missing the byte + { {(uint8_t[]){0x3d}, 1}, QCBOR_ERR_UNSUPPORTED }, // 1 byte integer missing the byte + { {(uint8_t[]){0x3e}, 1}, QCBOR_ERR_UNSUPPORTED }, // 1 byte integer missing the byte + { {(uint8_t[]){0x3f}, 1}, QCBOR_ERR_UNSUPPORTED }, // Indefinite length negative integer + { {(uint8_t[]){0x41}, 1}, QCBOR_ERR_HIT_END }, // Short byte string + { {(uint8_t[]){0x5c}, 1}, QCBOR_ERR_UNSUPPORTED }, // Reserved additional info = 28 + { {(uint8_t[]){0x5f}, 1}, QCBOR_ERR_UNSUPPORTED }, // Indefinite length byte string + { {(uint8_t[]){0x61}, 1}, QCBOR_ERR_HIT_END }, // Short UTF-8 string + { {(uint8_t[]){0x7c}, 1}, QCBOR_ERR_UNSUPPORTED }, // Reserved additional info = 28 + { {(uint8_t[]){0x7f}, 1}, QCBOR_ERR_UNSUPPORTED }, // Indefinite length UTF-8 string + { {(uint8_t[]){0xff}, 1}, QCBOR_ERR_UNSUPPORTED } , // break + { {(uint8_t[]){0xf8, 0x00}, 2}, QCBOR_ERR_INVALID_CBOR }, // An invalid encoding of a simple type + { {(uint8_t[]){0xf8, 0x1f}, 2}, QCBOR_ERR_INVALID_CBOR }, // An invalid encoding of a simple type + { {(uint8_t[]){0xc0, 0x00}, 2}, QCBOR_ERR_BAD_OPT_TAG }, // Text-based date, with an integer + { {(uint8_t[]){0xc1, 0x41, 0x33}, 3}, QCBOR_ERR_BAD_OPT_TAG }, // Epoch date, with an byte string + { {(uint8_t[]){0xc1, 0xc0, 0x00}, 3}, QCBOR_ERR_BAD_OPT_TAG }, // tagged as both epoch and string dates + { {(uint8_t[]){0xc2, 0x00}, 2}, QCBOR_ERR_BAD_OPT_TAG } // big num tagged an int, not a byte string + +}; + + +int FailureTests() +{ + int nResult = 0; + + struct FailInput *pFEnd = &Failures[0] + sizeof(Failures)/sizeof(struct FailInput); + + for(struct FailInput *pF = &Failures[0]; pF < pFEnd ;pF++) { + QCBORDecodeContext DCtx; + QCBORItem Item; + int nCBORError; + + QCBORDecode_Init(&DCtx, pF->Input, QCBOR_DECODE_MODE_NORMAL); + + while(1) { + nCBORError = QCBORDecode_GetNext(&DCtx, &Item); + if(QCBOR_ERR_HIT_END == nCBORError) { + break; + } + if(nCBORError != pF->nError) { + nResult = 1; + break; + } + } + } + + { + QCBORDecodeContext DCtx; + QCBORItem Item; + int nCBORError; + + QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spSimpleValues), QCBOR_DECODE_MODE_NORMAL); + + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) + return nCBORError; + if(Item.uDataType != QCBOR_TYPE_ARRAY || + Item.val.uCount != 10) + return -1; + + DCtx.InBuf.magic = 0; // Corrupt the UsefulInputBuf + + nCBORError = QCBORDecode_GetNext(&DCtx, &Item); + if(nCBORError != QCBOR_ERR_HIT_END) + return -1; + } + + + return nResult; +} + + +/* Try all 256 values of the byte at nLen including recursing for + each of the values to try values at nLen+1 ... up to nLenMax + */ +static void ComprehensiveInputRecurser(uint8_t *pBuf, int nLen, int nLenMax) +{ + if(nLen >= nLenMax) { + return; + } + + for(int inputByte = 0; inputByte < 256; inputByte++) { + // Set up the input + pBuf[nLen] = inputByte; + const UsefulBufC Input = {pBuf, nLen+1}; + + // Get ready to parse + QCBORDecodeContext DCtx; + QCBORDecode_Init(&DCtx, Input, QCBOR_DECODE_MODE_NORMAL); + + // Parse by getting the next item until an error occurs + // Just about every possible decoder error can occur here + // The goal of this test is not to check for the correct + // error since that is not really possible. It is to + // see that there is no crash on hostile input. + while(1) { + QCBORItem Item; + QCBORError nCBORError = QCBORDecode_GetNext(&DCtx, &Item); + if(nCBORError != QCBOR_SUCCESS) { + break; + } + } + + ComprehensiveInputRecurser(pBuf, nLen+1, nLenMax); + } +} + + +/* + Public function for initialization. See header qcbor.h + */ +int ComprehensiveInputTest() +{ + // Size 2 tests 64K inputs and runs quickly + uint8_t pBuf[2]; + + ComprehensiveInputRecurser(pBuf, 0, sizeof(pBuf)); + + return 0; +} + + +/* + Public function for initialization. See header qcbor.h + */ +int BigComprehensiveInputTest() +{ + // size 3 tests 16 million inputs and runs OK + // in seconds on fast machines. Size 4 takes + // 10+ minutes and 5 half a day on fast + // machines. This test is kept separate from + // the others so as to no slow down the use + // of them as a very frequent regression. + uint8_t pBuf[3]; // + + ComprehensiveInputRecurser(pBuf, 0, sizeof(pBuf)); + + return 0; +} + + +static uint8_t spDateTestInput[] = { + 0xc0, // tag for string date + 0x6a, '1','9','8','5','-','0','4','-','1','2', // Date string + + 0xc1, // tag for epoch date + 0x1a, 0x53, 0x72, 0x4E, 0x00, // Epoch date 1400000000; Tue, 13 May 2014 16:53:20 GMT + + // CBOR_TAG_B64 + 0xc1, 0xcf, 0xd8, 0x22, // 0xee, // Epoch date with extra tags TODO: fix this test + 0x1a, 0x53, 0x72, 0x4E, 0x01, + + 0xc1, // tag for epoch date + 0x1b, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // Too large integer + + 0xc1, // tag for epoch date + 0xfa, 0x3f, 0x8c, 0xcc, 0xcd, // double with value 1.1 + + 0xc1, // tag for epoch date + 0xfa, 0x7f, 0x7f, 0xff, 0xff // 3.4028234663852886e+38 too large + +}; + + +// have to check float expected only to within an epsilon +int CHECK_EXPECTED_DOUBLE(double val, double expected) { + + double diff = val - expected; + + diff = fabs(diff); + + return diff > 0.0000001; +} + + +int DateParseTest() +{ + QCBORDecodeContext DCtx; + QCBORItem Item; + int nCBORError; + + QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spDateTestInput), QCBOR_DECODE_MODE_NORMAL); + + const uint64_t uTags[] = {15}; + QCBORTagListIn TagList = {1, uTags}; + + QCBORDecode_SetCallerConfiguredTagList(&DCtx, &TagList); + + // String date + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) + return -1; + if(Item.uDataType != QCBOR_TYPE_DATE_STRING || + UsefulBuf_Compare(Item.val.dateString, UsefulBuf_FromSZ("1985-04-12"))){ + return -2; + } + + // Epoch date + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) + return -3; + if(Item.uDataType != QCBOR_TYPE_DATE_EPOCH || + Item.val.epochDate.nSeconds != 1400000000 || + Item.val.epochDate.fSecondsFraction != 0 ) { + return -4; + } + + // Epoch date with extra CBOR_TAG_B64 tag that doesn't really mean anything + // but want to be sure extra tag doesn't cause a problem + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) + return -5; + if(Item.uDataType != QCBOR_TYPE_DATE_EPOCH || + Item.val.epochDate.nSeconds != 1400000001 || + Item.val.epochDate.fSecondsFraction != 0 || + !QCBORDecode_IsTagged(&DCtx, &Item, CBOR_TAG_B64)) { + return -6; + } + + // Epoch date that is too large for our representation + if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_DATE_OVERFLOW) { + return -7; + } + + // Epoch date in float format with fractional seconds + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) + return -8; + if(Item.uDataType != QCBOR_TYPE_DATE_EPOCH || + Item.val.epochDate.nSeconds != 1 || + CHECK_EXPECTED_DOUBLE(Item.val.epochDate.fSecondsFraction, 0.1 )) { + return -9; + } + + // Epoch date float that is too large for our representation + if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_DATE_OVERFLOW) { + return -10; + } + + // TODO: could use a few more tests with float, double, and half precsion and negative (but coverage is still pretty good) + + return 0; +} + +// Really simple basic input for tagging test +static uint8_t spOptTestInput[] = { + 0xd9, 0xd9, 0xf7, // CBOR magic number + 0x81, // Array of one + 0xd8, 0x04, // non-preferred serialization of tag 4 + 0x82, 0x01, 0x03}; // fraction 1/3 + +static uint8_t spEncodedLargeTag[] = {0xdb, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x80}; + +// 0x9192939495969798, 0x88, 0x01, 0x04 +static uint8_t spLotsOfTags[] = {0xdb, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0xd8, 0x88, 0xc5, 0xc4, 0x80}; + +/* + The cbor.me parse of this. + 55799(55799(55799({6(7(-23)): 5859837686836516696(7({7(-20): 11({17(-18): 17(17(17("Organization"))), + 9(-17): 773("SSG"), -15: 4(5(6(7(8(9(10(11(12(13(14(15("Confusion")))))))))))), 17(-16): 17("San Diego"), + 17(-14): 17("US")}), 23(-19): 19({-11: 9({-9: -7}), + 90599561(90599561(90599561(-10))): 12(h'0102030405060708090A')})})), + 16(-22): 23({11(8(7(-5))): 8(-3)})}))) + */ +static uint8_t spCSRWithTags[] = { + 0xd9, 0xd9, 0xf7, 0xd9, 0xd9, 0xf7, 0xd9, 0xd9, 0xf7, 0xa2, + 0xc6, 0xc7, 0x36, + 0xdb, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0xc7, 0xa2, + 0xda, 0x00, 0x00, 0x00, 0x07, 0x33, + 0xcb, 0xa5, + 0xd1, 0x31, + 0xd1, 0xd1, 0xd1, 0x6c, + 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0xc9, 0x30, + 0xd9, 0x03, 0x05, 0x63, + 0x53, 0x53, 0x47, + 0x2e, + 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0x69, + 0x43, 0x6f, 0x6e, 0x66, 0x75, 0x73, 0x69, 0x6f, 0x6e, + 0xd1, 0x2f, + 0xd1, 0x69, + 0x53, 0x61, 0x6e, 0x20, 0x44, 0x69, 0x65, 0x67, 0x6f, + 0xd1, 0x2d, + 0xd1, 0x62, + 0x55, 0x53, + 0xd7, 0x32, + 0xd3, 0xa2, + 0x2a, + 0xc9, 0xa1, + 0x28, + 0x26, + 0xda, 0x05, 0x66, 0x70, 0x89, 0xda, 0x05, 0x66, 0x70, 0x89, 0xda, 0x05, 0x66, 0x70, 0x89, 0x29, + 0xcc, 0x4a, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,0x07, 0x08, 0x09, 0x0a, + 0xd0, 0x35, + 0xd7, 0xa1, + 0xcb, 0xc8, 0xc7, 0x24, + 0xc8, 0x22}; + +static int CheckCSRMaps(QCBORDecodeContext *pDC); + + +int OptTagParseTest() +{ + QCBORDecodeContext DCtx; + QCBORItem Item; + + QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spOptTestInput), QCBOR_DECODE_MODE_NORMAL); + + //------------------------- + // This text matches the magic number tag and the fraction tag + if(QCBORDecode_GetNext(&DCtx, &Item)) { + return -2; + } + if(Item.uDataType != QCBOR_TYPE_ARRAY || + !QCBORDecode_IsTagged(&DCtx, &Item, CBOR_TAG_CBOR_MAGIC)) { + return -3; + } + + if(QCBORDecode_GetNext(&DCtx, &Item)) { + return -4; + } + if(Item.uDataType != QCBOR_TYPE_ARRAY || + !QCBORDecode_IsTagged(&DCtx, &Item, CBOR_TAG_FRACTION) || + Item.val.uCount != 2) { + return -5; + } + + // -------------------------------- + // This test decodes the very large tag, but it is not in + // any list so it is ignored. + QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spEncodedLargeTag), QCBOR_DECODE_MODE_NORMAL); + if(QCBORDecode_GetNext(&DCtx, &Item)) { + return -6; + } + if(Item.uTagBits) { + return -7; + } + + // ---------------------------------- + // This test sets up a caller-config list that includes the very large tage and then matches it. + QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spEncodedLargeTag), QCBOR_DECODE_MODE_NORMAL); + const uint64_t puList[] = {0x9192939495969798, 257}; + const QCBORTagListIn TL = {2, puList}; + QCBORDecode_SetCallerConfiguredTagList(&DCtx, &TL); + + if(QCBORDecode_GetNext(&DCtx, &Item)) { + return -8; + } + if(Item.uDataType != QCBOR_TYPE_ARRAY || + !QCBORDecode_IsTagged(&DCtx, &Item, 0x9192939495969798) || + QCBORDecode_IsTagged(&DCtx, &Item, 257) || + QCBORDecode_IsTagged(&DCtx, &Item, CBOR_TAG_BIGFLOAT) || + Item.val.uCount != 0) { + return -9; + } + + //------------------------ + // This test sets up a caller-configured list, and looks up something not in it + const uint64_t puLongList[17] = {1,2,1}; + const QCBORTagListIn TLLong = {17, puLongList}; + QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spEncodedLargeTag), QCBOR_DECODE_MODE_NORMAL); + QCBORDecode_SetCallerConfiguredTagList(&DCtx, &TLLong); + if(QCBORDecode_GetNext(&DCtx, &Item)) { + return -11; + } + + // ----------------------- + // This tests retrievel of the full tag list + QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spLotsOfTags), QCBOR_DECODE_MODE_NORMAL); + uint64_t puTags[16]; + QCBORTagListOut Out = {0, 4, puTags}; + if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { + return -12; + } + if(puTags[0] != 0x9192939495969798 || + puTags[1] != 0x88 || + puTags[2] != 0x05 || + puTags[3] != 0x04) { + return -13; + } + + // ---------------------- + // This text if too small of an out list + QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spLotsOfTags), QCBOR_DECODE_MODE_NORMAL); + QCBORTagListOut OutSmall = {0, 3, puTags}; + if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &OutSmall) != QCBOR_ERR_TOO_MANY_TAGS) { + return -14; + } + + // --------------- + // Parse a version of the "CSR" that has had a ton of tags randomly inserted + QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spCSRWithTags), QCBOR_DECODE_MODE_NORMAL); + int n = CheckCSRMaps(&DCtx); + if(n) { + return n-2000; + } + + Out = (QCBORTagListOut){0,16, puTags}; + QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spCSRWithTags), QCBOR_DECODE_MODE_NORMAL); + + const uint64_t puTagList[] = {773, 1, 90599561}; + const QCBORTagListIn TagList = {3, puTagList}; + QCBORDecode_SetCallerConfiguredTagList(&DCtx, &TagList); + + + if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { + return -100; + } + if(Item.uDataType != QCBOR_TYPE_MAP || + !QCBORDecode_IsTagged(&DCtx, &Item, CBOR_TAG_CBOR_MAGIC) || + QCBORDecode_IsTagged(&DCtx, &Item, 90599561) || + QCBORDecode_IsTagged(&DCtx, &Item, CBOR_TAG_DATE_EPOCH) || + Item.val.uCount != 2 || + puTags[0] != CBOR_TAG_CBOR_MAGIC || + puTags[1] != CBOR_TAG_CBOR_MAGIC || + puTags[2] != CBOR_TAG_CBOR_MAGIC || + Out.uNumUsed != 3) { + return -101; + } + + if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { + return -102; + } + if(Item.uDataType != QCBOR_TYPE_MAP || + QCBORDecode_IsTagged(&DCtx, &Item, CBOR_TAG_CBOR_MAGIC) || + QCBORDecode_IsTagged(&DCtx, &Item, 6) || + QCBORDecode_IsTagged(&DCtx, &Item, 7) || // item is tagged 7, but 7 is not configured to be recognized + Item.val.uCount != 2 || + puTags[0] != 5859837686836516696 || + puTags[1] != 7 || + Out.uNumUsed != 2) { + return -103; + } + + if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { + return -104; + } + if(Item.uDataType != QCBOR_TYPE_MAP || + Item.uTagBits || + Item.val.uCount != 5 || + puTags[0] != 0x0b || + Out.uNumUsed != 1) { + return -105; + } + + if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { + return -106; + } + if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || + !QCBORDecode_IsTagged(&DCtx, &Item, CBOR_TAG_COSE_MAC0) || + Item.val.string.len != 12 || + puTags[0] != CBOR_TAG_COSE_MAC0 || + puTags[1] != CBOR_TAG_COSE_MAC0 || + puTags[2] != CBOR_TAG_COSE_MAC0 || + Out.uNumUsed != 3) { + return -105; + } + + if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { + return -107; + } + if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || + !QCBORDecode_IsTagged(&DCtx, &Item, 773) || + Item.val.string.len != 3 || + puTags[0] != 773 || + Out.uNumUsed != 1) { + return -108; + } + + if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { + return -109; + } + if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || + !QCBORDecode_IsTagged(&DCtx, &Item, 4) || + Item.val.string.len != 9 || + puTags[0] != 4 || + puTags[11] != 0x0f || + Out.uNumUsed != 12) { + return -110; + } + + if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { + return -111; + } + if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || + !QCBORDecode_IsTagged(&DCtx, &Item, 17) || + Item.val.string.len != 9 || + puTags[0] != 17 || + Out.uNumUsed != 1) { + return -112; + } + + if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { + return -111; + } + if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || + !QCBORDecode_IsTagged(&DCtx, &Item, 17) || + Item.val.string.len != 2 || + puTags[0] != 17 || + Out.uNumUsed != 1) { + return -112; + } + + if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { + return -113; + } + if(Item.uDataType != QCBOR_TYPE_MAP || + QCBORDecode_IsTagged(&DCtx, &Item, 19) || + Item.val.uCount != 2 || + puTags[0] != 19 || + Out.uNumUsed != 1) { + return -114; + } + + if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { + return -115; + } + if(Item.uDataType != QCBOR_TYPE_MAP || + QCBORDecode_IsTagged(&DCtx, &Item, 9) || + Item.uTagBits || + Item.val.uCount != 1 || + puTags[0] != 9 || + Out.uNumUsed != 1) { + return -116; + } + + if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { + return -116; + } + if(Item.uDataType != QCBOR_TYPE_INT64 || + Item.val.int64 != -7 || + Item.uTagBits || + Out.uNumUsed != 0) { + return -117; + } + + if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { + return -118; + } + if(Item.uDataType != QCBOR_TYPE_BYTE_STRING || + Item.val.string.len != 10 || + Item.uTagBits || + puTags[0] != 12 || + Out.uNumUsed != 1) { + return -119; + } + + if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { + return -120; + } + if(Item.uDataType != QCBOR_TYPE_MAP || + !QCBORDecode_IsTagged(&DCtx, &Item, CBOR_TAG_ENC_AS_B16) || + Item.val.uCount != 1 || + puTags[0] != 0x17 || + Out.uNumUsed != 1) { + return -121; + } + + if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { + return -122; + } + if(Item.uDataType != QCBOR_TYPE_INT64 || + QCBORDecode_IsTagged(&DCtx, &Item, 8) || + Item.val.int64 != -3 || + puTags[0] != 8 || + Out.uNumUsed != 1) { + return -123; + } + + if(QCBORDecode_Finish(&DCtx)) { + return -124; + } + + return 0; +} + + + + +static uint8_t spBigNumInput[] = { + 0x83, + 0xC2, 0x49, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xC3, 0x49, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xA4, + 0x63, 0x42, 0x4E, 0x2B, + 0xC2, 0x49, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x40, + 0xC2, 0x49, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x63, 0x42, 0x4E, 0x2D, + 0xC3, 0x49, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x38, 0x3F, + 0xC3, 0x49, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + + +static uint8_t spBigNum[] = {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + + +int BignumParseTest() +{ + QCBORDecodeContext DCtx; + QCBORItem Item; + int nCBORError; + + QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBigNumInput), QCBOR_DECODE_MODE_NORMAL); + + + // + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) + return -1; + if(Item.uDataType != QCBOR_TYPE_ARRAY) { + return -1; + } + + // + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) + return -1; + if(Item.uDataType != QCBOR_TYPE_POSBIGNUM || + UsefulBuf_Compare(Item.val.bigNum, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBigNum))){ + return -1; + } + + // + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) + return -1; + if(Item.uDataType != QCBOR_TYPE_NEGBIGNUM || + UsefulBuf_Compare(Item.val.bigNum, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBigNum))){ + return -1; + } + + // + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) + return -1; + if(Item.uDataType != QCBOR_TYPE_MAP) { + return -1; + } + + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) + return -1; + if(Item.uDataType != QCBOR_TYPE_POSBIGNUM || + Item.uLabelType != QCBOR_TYPE_TEXT_STRING || + UsefulBuf_Compare(Item.val.bigNum, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBigNum))){ + return -1; + } + + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) + return -1; + if(Item.uDataType != QCBOR_TYPE_POSBIGNUM || + Item.uLabelType != QCBOR_TYPE_INT64 || + Item.label.int64 != 64 || + UsefulBuf_Compare(Item.val.bigNum, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBigNum))){ + return -1; + } + + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) + return -1; + if(Item.uDataType != QCBOR_TYPE_NEGBIGNUM || + Item.uLabelType != QCBOR_TYPE_TEXT_STRING || + UsefulBuf_Compare(Item.val.bigNum, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBigNum))){ + return -1; + } + + if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) + return -1; + if(Item.uDataType != QCBOR_TYPE_NEGBIGNUM || + Item.uLabelType != QCBOR_TYPE_INT64 || + Item.label.int64 != -64 || + UsefulBuf_Compare(Item.val.bigNum, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBigNum))){ + return -1; + } + + return 0; +} + + + +static int CheckItemWithIntLabel(QCBORDecodeContext *pCtx, uint8_t uDataType, uint8_t uNestingLevel, uint8_t uNextNest, int64_t nLabel, QCBORItem *pItem) +{ + QCBORItem Item; + int nCBORError; + + if((nCBORError = QCBORDecode_GetNext(pCtx, &Item))) return -1; + if(Item.uDataType != uDataType) return -1; + if(uNestingLevel > 0) { + if(Item.uLabelType != QCBOR_TYPE_INT64 && Item.uLabelType != QCBOR_TYPE_UINT64) return -1; + if(Item.uLabelType == QCBOR_TYPE_INT64) { + if(Item.label.int64 != nLabel) return -1; + } else { + if(Item.label.uint64 != (uint64_t)nLabel) return -1; + } + } + if(Item.uNestingLevel != uNestingLevel) return -1; + if(Item.uNextNestLevel != uNextNest) return -1; + + if(pItem) { + *pItem = Item; + } + return 0; +} + + +// Same code checks definite and indefinite length versions of the map +static int CheckCSRMaps(QCBORDecodeContext *pDC) +{ + if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_MAP, 0, 1, 0, NULL)) return -1; + + if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_MAP, 1, 2, -23, NULL)) return -1; + + if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_MAP, 2, 3, -20, NULL)) return -1; + + if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_TEXT_STRING, 3, 3, -18, NULL)) return -1; + if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_TEXT_STRING, 3, 3, -17, NULL)) return -1; + if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_TEXT_STRING, 3, 3, -15, NULL)) return -1; + if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_TEXT_STRING, 3, 3, -16, NULL)) return -1; + if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_TEXT_STRING, 3, 2, -14, NULL)) return -1; + + if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_MAP, 2, 3, -19, NULL)) return -1; + if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_MAP, 3, 4, -11, NULL)) return -1; + + if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_INT64, 4, 3, -9, NULL)) return -1; + if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_BYTE_STRING, 3, 1, -10, NULL)) return -1; + + if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_MAP, 1, 2, -22, NULL)) return -1; + if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_INT64, 2, 0, -5, NULL)) return -1; + + if(QCBORDecode_Finish(pDC)) return -2; + + return 0; +} + + +/* +// cbor.me decoded output +{ + -23: { + -20: { + -18: "Organization", + -17: "SSG", + -15: "Confusion", + -16: "San Diego", + -14: "US" + }, + -19: { + -11: { + -9: -7 + }, + -10: '\u0001\u0002\u0003\u0004\u0005\u0006\a\b\t\n' + } + }, + -22: { + -5: -3 + } +} + */ + + +static uint8_t spCSRInput[] = { + 0xa2, 0x36, 0xa2, 0x33, 0xa5, 0x31, 0x6c, 0x4f, + 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x30, 0x63, 0x53, 0x53, 0x47, + 0x2e, 0x69, 0x43, 0x6f, 0x6e, 0x66, 0x75, 0x73, + 0x69, 0x6f, 0x6e, 0x2f, 0x69, 0x53, 0x61, 0x6e, + 0x20, 0x44, 0x69, 0x65, 0x67, 0x6f, 0x2d, 0x62, + 0x55, 0x53, 0x32, 0xa2, 0x2a, 0xa1, 0x28, 0x26, + 0x29, 0x4a, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, + 0x07, 0x08, 0x09, 0x0a, 0x35, 0xa1, 0x24, 0x22}; + +int NestedMapTest() +{ + QCBORDecodeContext DCtx; + + QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spCSRInput), QCBOR_DECODE_MODE_NORMAL); + + return CheckCSRMaps(&DCtx); +} + + + +int StringDecoderModeFailTest() +{ + QCBORDecodeContext DCtx; + + QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spCSRInput), QCBOR_DECODE_MODE_MAP_STRINGS_ONLY); + + QCBORItem Item; + QCBORError nCBORError; + + if(QCBORDecode_GetNext(&DCtx, &Item)) { + return -1; + } + if(Item.uDataType != QCBOR_TYPE_MAP) { + return -2; + } + + nCBORError = QCBORDecode_GetNext(&DCtx, &Item); + if(nCBORError != QCBOR_ERR_MAP_LABEL_TYPE) { + return -3; + } + + return 0; +} + + +// Same map as above, but using indefinite lengths +static uint8_t spCSRInputIndefLen[] = { + 0xbf, 0x36, 0xbf, 0x33, 0xbf, 0x31, 0x6c, 0x4f, + 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x30, 0x63, 0x53, 0x53, 0x47, + 0x2e, 0x69, 0x43, 0x6f, 0x6e, 0x66, 0x75, 0x73, + 0x69, 0x6f, 0x6e, 0x2f, 0x69, 0x53, 0x61, 0x6e, + 0x20, 0x44, 0x69, 0x65, 0x67, 0x6f, 0x2d, 0x62, + 0x55, 0x53, 0xff, 0x32, 0xbf, 0x2a, 0xbf, 0x28, + 0x26, 0xff, 0x29, 0x4a, 0x01, 0x02, 0x03, 0x04, + 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0xff, 0xff, + 0x35, 0xbf, 0x24, 0x22, 0xff, 0xff}; + +int NestedMapTestIndefLen() +{ + QCBORDecodeContext DCtx; + + QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spCSRInputIndefLen), QCBOR_DECODE_MODE_NORMAL); + + return CheckCSRMaps(&DCtx); +} + + + +static UsefulBufC make_nested_indefinite_arrays(int n, UsefulBuf Storage) +{ + UsefulOutBuf UOB; + UsefulOutBuf_Init(&UOB, Storage); + + int i; + for(i = 0; i < n; i++) { + UsefulOutBuf_AppendByte(&UOB, 0x9f); + } + + for(i = 0; i < n; i++) { + UsefulOutBuf_AppendByte(&UOB, 0xff); + } + return UsefulOutBuf_OutUBuf(&UOB); +} + + +static int parse_indeflen_nested(UsefulBufC Nested, int nNestLevel) +{ + QCBORDecodeContext DC; + QCBORDecode_Init(&DC, Nested, 0); + + int j; + for(j = 0; j < nNestLevel; j++) { + QCBORItem Item; + int nReturn = QCBORDecode_GetNext(&DC, &Item); + if(j >= QCBOR_MAX_ARRAY_NESTING) { + // Should be in error + if(nReturn != QCBOR_ERR_ARRAY_NESTING_TOO_DEEP) { + return -4; + } else { + return 0; // Decoding doesn't recover after an error + } + } else { + // Should be no error + if(nReturn) { + return -9; // Should not have got an error + } + } + if(Item.uDataType != QCBOR_TYPE_ARRAY) { + return -7; + } + } + int nReturn = QCBORDecode_Finish(&DC); + if(nReturn) { + return -3; + } + return 0; +} + + +int IndefiniteLengthNestTest() +{ + UsefulBuf_MAKE_STACK_UB(Storage, 50); + int i; + for(i=1; i < QCBOR_MAX_ARRAY_NESTING+4; i++) { + const UsefulBufC Nested = make_nested_indefinite_arrays(i, Storage); + int nReturn = parse_indeflen_nested(Nested, i); + if(nReturn) { + return nReturn; + } + } + return 0; +} + + + +static const uint8_t spIndefiniteArray[] = {0x9f, 0x01, 0x82, 0x02, 0x03, 0xff}; // [1, [2, 3]] +static const uint8_t spIndefiniteArrayBad1[] = {0x9f}; // No closing break +static const uint8_t spIndefiniteArrayBad2[] = {0x9f, 0x9f, 0x02, 0xff}; // Not enough closing breaks +static const uint8_t spIndefiniteArrayBad3[] = {0x9f, 0x02, 0xff, 0xff}; // Too many closing breaks +static const uint8_t spIndefiniteArrayBad4[] = {0x81, 0x9f}; // Unclosed indeflen inside def len +static const uint8_t spIndefiniteArrayBad5[] = {0x9f, 0xd1, 0xff}; // confused tag + +int IndefiniteLengthArrayMapTest() +{ + int nResult; + // --- first test ----- + UsefulBufC IndefLen = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteArray); + + // Decode it and see if it is OK + UsefulBuf_MAKE_STACK_UB(MemPool, 150); + QCBORDecodeContext DC; + QCBORItem Item; + QCBORDecode_Init(&DC, IndefLen, QCBOR_DECODE_MODE_NORMAL); + + QCBORDecode_SetMemPool(&DC, MemPool, false); + + QCBORDecode_GetNext(&DC, &Item); + + if(Item.uDataType != QCBOR_TYPE_ARRAY || + Item.uNestingLevel != 0 || + Item.uNextNestLevel != 1) { + return -111; + } + + QCBORDecode_GetNext(&DC, &Item); + if(Item.uDataType != QCBOR_TYPE_INT64 || + Item.uNestingLevel != 1 || + Item.uNextNestLevel != 1) { + return -2; + } + + QCBORDecode_GetNext(&DC, &Item); + if(Item.uDataType != QCBOR_TYPE_ARRAY || + Item.uNestingLevel != 1 || + Item.uNextNestLevel != 2) { + return -3; + } + + QCBORDecode_GetNext(&DC, &Item); + if(Item.uDataType != QCBOR_TYPE_INT64 || + Item.uNestingLevel != 2 || + Item.uNextNestLevel != 2) { + return -4; + } + + QCBORDecode_GetNext(&DC, &Item); + if(Item.uDataType != QCBOR_TYPE_INT64 || + Item.uNestingLevel != 2 || + Item.uNextNestLevel != 0) { + return -5; + } + + if(QCBORDecode_Finish(&DC)) { + return -6; + } + + // --- next test ----- + IndefLen = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteArrayBad1); + + QCBORDecode_Init(&DC, IndefLen, QCBOR_DECODE_MODE_NORMAL); + + QCBORDecode_SetMemPool(&DC, MemPool, false); + + nResult = QCBORDecode_GetNext(&DC, &Item); + if(nResult || Item.uDataType != QCBOR_TYPE_ARRAY) { + return -7; + } + + nResult = QCBORDecode_Finish(&DC); + if(nResult != QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN) { + return -8; + } + + + // --- next test ----- + IndefLen = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteArrayBad2); + + QCBORDecode_Init(&DC, IndefLen, QCBOR_DECODE_MODE_NORMAL); + + QCBORDecode_SetMemPool(&DC, MemPool, false); + + nResult = QCBORDecode_GetNext(&DC, &Item); + if(nResult || Item.uDataType != QCBOR_TYPE_ARRAY) { + return -9; + } + + nResult = QCBORDecode_GetNext(&DC, &Item); + if(nResult || Item.uDataType != QCBOR_TYPE_ARRAY) { + return -10; + } + + nResult = QCBORDecode_GetNext(&DC, &Item); + if(nResult || Item.uDataType != QCBOR_TYPE_INT64) { + return -11; + } + + nResult = QCBORDecode_Finish(&DC); + if(nResult != QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN) { + return -12; + } + + + // --- next test ----- + IndefLen = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteArrayBad3); + + QCBORDecode_Init(&DC, IndefLen, QCBOR_DECODE_MODE_NORMAL); + + QCBORDecode_SetMemPool(&DC, MemPool, false); + + nResult = QCBORDecode_GetNext(&DC, &Item); + if(nResult || Item.uDataType != QCBOR_TYPE_ARRAY) { + return -13; + } + + nResult = QCBORDecode_GetNext(&DC, &Item); + if(nResult != QCBOR_ERR_BAD_BREAK) { + return -14; + } + + + // --- next test ----- + IndefLen = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteArrayBad4); + + QCBORDecode_Init(&DC, IndefLen, QCBOR_DECODE_MODE_NORMAL); + + QCBORDecode_SetMemPool(&DC, MemPool, false); + + nResult = QCBORDecode_GetNext(&DC, &Item); + if(nResult || Item.uDataType != QCBOR_TYPE_ARRAY) { + return -15; + } + + nResult = QCBORDecode_GetNext(&DC, &Item); + if(nResult || Item.uDataType != QCBOR_TYPE_ARRAY) { + return -16; + } + + nResult = QCBORDecode_Finish(&DC); + if(nResult != QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN) { + return -17; + } + + // --- next test ----- + IndefLen = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteArrayBad5); + + QCBORDecode_Init(&DC, IndefLen, QCBOR_DECODE_MODE_NORMAL); + + QCBORDecode_SetMemPool(&DC, MemPool, false); + + nResult = QCBORDecode_GetNext(&DC, &Item); + if(nResult || Item.uDataType != QCBOR_TYPE_ARRAY) { + return -18; + } + + nResult = QCBORDecode_GetNext(&DC, &Item); + if(nResult != QCBOR_ERR_BAD_BREAK) { + return -19; + } + + return 0; +} + + +static const uint8_t spIndefiniteLenString[] = { + 0x81, // Array of length one + 0x7f, // text string marked with indefinite length + 0x65, 0x73, 0x74, 0x72, 0x65, 0x61, // first segment + 0x64, 0x6d, 0x69, 0x6e, 0x67, // second segment + 0xff // ending break +}; + +static const uint8_t spIndefiniteLenStringBad2[] = { + 0x81, // Array of length one + 0x7f, // text string marked with indefinite length + 0x65, 0x73, 0x74, 0x72, 0x65, 0x61, // first segment + 0x44, 0x6d, 0x69, 0x6e, 0x67, // second segment of wrong type + 0xff // ending break +}; + +static const uint8_t spIndefiniteLenStringBad3[] = { + 0x81, // Array of length one + 0x7f, // text string marked with indefinite length + 0x01, 0x02, // Not a string + 0xff // ending break +}; + +static const uint8_t spIndefiniteLenStringBad4[] = { + 0x81, // Array of length one + 0x7f, // text string marked with indefinite length + 0x65, 0x73, 0x74, 0x72, 0x65, 0x61, // first segment + 0x64, 0x6d, 0x69, 0x6e, 0x67, // second segment + // missing end of string +}; + +static const uint8_t spIndefiniteLenStringLabel[] = { + 0xa1, // Array of length one + 0x7f, // text string marked with indefinite length + 0x65, 0x73, 0x74, 0x72, 0x75, 0x75, // first segment + 0x64, 0x6d, 0x69, 0x6e, 0x67, // second segment + 0xff, // ending break + 0x01 // integer being labeled. +}; + +static UsefulBufC MakeIndefiniteBigBstr(UsefulBuf Storage) // TODO: size this +{ + UsefulOutBuf UOB; + + UsefulOutBuf_Init(&UOB, Storage); + UsefulOutBuf_AppendByte(&UOB, 0x81); + UsefulOutBuf_AppendByte(&UOB, 0x5f); + + int i = 0; + for(int nChunkSize = 1; nChunkSize <= 128; nChunkSize *= 2) { + UsefulOutBuf_AppendByte(&UOB, 0x58); + UsefulOutBuf_AppendByte(&UOB, (uint8_t)nChunkSize); + for(int j = 0; j < nChunkSize; j++ ) { + UsefulOutBuf_AppendByte(&UOB, i); + i++; + } + } + UsefulOutBuf_AppendByte(&UOB, 0xff); + + return UsefulOutBuf_OutUBuf(&UOB); +} + +static int CheckBigString(UsefulBufC BigString) +{ + if(BigString.len != 255) { + return 1; + } + + for(uint8_t i = 0; i < 255; i++){ + if(((const uint8_t *)BigString.ptr)[i] != i) { + return 1; + } + } + return 0; +} + + +int IndefiniteLengthStringTest() +{ + QCBORDecodeContext DC; + QCBORItem Item; + // big enough for MakeIndefiniteBigBstr() + MemPool overhead + UsefulBuf_MAKE_STACK_UB(MemPool, 350); + + // --- Simple normal indefinite length string ------ + UsefulBufC IndefLen = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteLenString); + QCBORDecode_Init(&DC, IndefLen, QCBOR_DECODE_MODE_NORMAL); + + if(QCBORDecode_SetMemPool(&DC, MemPool, false)) { + return -1; + } + + if(QCBORDecode_GetNext(&DC, &Item)) { + return -2; + } + if(Item.uDataType != QCBOR_TYPE_ARRAY || Item.uDataAlloc) { + return -3; + } + + if(QCBORDecode_GetNext(&DC, &Item)) { + return -4; + } + if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || !Item.uDataAlloc) { + return -5; + } + if(QCBORDecode_Finish(&DC)) { + return -6; + } + + // ----- types mismatch --- + QCBORDecode_Init(&DC, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteLenStringBad2), QCBOR_DECODE_MODE_NORMAL); + + if(QCBORDecode_SetMemPool(&DC, MemPool, false)) { + return -7; + } + + if(QCBORDecode_GetNext(&DC, &Item)) { + return -8; + } + if(Item.uDataType != QCBOR_TYPE_ARRAY) { + return -9; + } + + if(QCBORDecode_GetNext(&DC, &Item) != QCBOR_ERR_INDEFINITE_STRING_CHUNK) { + return -10; + } + + // ----- not a string --- + QCBORDecode_Init(&DC, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteLenStringBad3), QCBOR_DECODE_MODE_NORMAL); + + if(QCBORDecode_SetMemPool(&DC, MemPool, false)) { + return -11; + } + + if(QCBORDecode_GetNext(&DC, &Item)) { + return -12; + } + if(Item.uDataType != QCBOR_TYPE_ARRAY) { + return -13; + } + + if(QCBORDecode_GetNext(&DC, &Item) != QCBOR_ERR_INDEFINITE_STRING_CHUNK) { + return -14; + } + + // ----- no end ----- + QCBORDecode_Init(&DC, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteLenStringBad4), QCBOR_DECODE_MODE_NORMAL); + + if(QCBORDecode_SetMemPool(&DC, MemPool, false)) { + return -15; + } + + if(QCBORDecode_GetNext(&DC, &Item)) { + return -16; + } + if(Item.uDataType != QCBOR_TYPE_ARRAY) { + return -17; + } + + if(QCBORDecode_GetNext(&DC, &Item) != QCBOR_ERR_HIT_END) { + return -18; + } + + // ------ Don't set a string allocator and see an error ----- + QCBORDecode_Init(&DC, IndefLen, QCBOR_DECODE_MODE_NORMAL); + + QCBORDecode_GetNext(&DC, &Item); + if(Item.uDataType != QCBOR_TYPE_ARRAY) { + return -19; + } + + if(QCBORDecode_GetNext(&DC, &Item) != QCBOR_ERR_NO_STRING_ALLOCATOR) { + return -20; + } + + // ----- Mempool is way too small ----- + UsefulBuf_MAKE_STACK_UB(MemPoolTooSmall, 20); // 20 is too small no matter what + + QCBORDecode_Init(&DC, IndefLen, QCBOR_DECODE_MODE_NORMAL); + if(!QCBORDecode_SetMemPool(&DC, MemPoolTooSmall, false)) { + return -21; + } + + // ----- Mempool is way too small ----- + UsefulBuf_MAKE_STACK_UB(BigIndefBStrStorage, 290); + const UsefulBufC BigIndefBStr = MakeIndefiniteBigBstr(BigIndefBStrStorage); + + UsefulBuf_MAKE_STACK_UB(MemPoolSmall, 80); // 80 is big enough for MemPool overhead, but not BigIndefBStr + + QCBORDecode_Init(&DC, BigIndefBStr, QCBOR_DECODE_MODE_NORMAL); + if(QCBORDecode_SetMemPool(&DC, MemPoolSmall, false)) { + return -22; + } + + QCBORDecode_GetNext(&DC, &Item); + if(Item.uDataType != QCBOR_TYPE_ARRAY) { + return -23; + } + if(QCBORDecode_GetNext(&DC, &Item) != QCBOR_ERR_STRING_ALLOCATE) { + return -24; + } + + // ---- big bstr ----- + QCBORDecode_Init(&DC, BigIndefBStr, QCBOR_DECODE_MODE_NORMAL); + + if(QCBORDecode_SetMemPool(&DC, MemPool, false)) { + return -25; + } + + if(QCBORDecode_GetNext(&DC, &Item)) { + return -26; + } + if(Item.uDataType != QCBOR_TYPE_ARRAY || Item.uDataAlloc) { + return -26; + } + + if(QCBORDecode_GetNext(&DC, &Item)) { + return -27; + } + if(Item.uDataType != QCBOR_TYPE_BYTE_STRING || !Item.uDataAlloc || Item.uNestingLevel != 1) { + return -28; + } + if(CheckBigString(Item.val.string)) { + return -3; + } + if(QCBORDecode_Finish(&DC)) { + return -29; + } + + // --- label is an indefinite length string ------ + QCBORDecode_Init(&DC, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteLenStringLabel), QCBOR_DECODE_MODE_NORMAL); + + if(QCBORDecode_SetMemPool(&DC, MemPool, false)) { + return -30; + } + + QCBORDecode_GetNext(&DC, &Item); + if(Item.uDataType != QCBOR_TYPE_MAP) { + return -31; + } + + if(QCBORDecode_GetNext(&DC, &Item)){ + return -32; + } + if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || Item.uDataType != QCBOR_TYPE_INT64 || + Item.uDataAlloc || !Item.uLabelAlloc || + UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("struuming"))) { + return -33; + } + + if(QCBORDecode_Finish(&DC)) { + return -34; + } + + return 0; +} + + +int AllocAllStringsTest() +{ + QCBORDecodeContext DC; + QCBORError nCBORError; + + + // First test, use the "CSRMap" as easy input and checking + QCBORDecode_Init(&DC, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spCSRInput), QCBOR_DECODE_MODE_NORMAL); + + UsefulBuf_MAKE_STACK_UB(Pool, sizeof(spCSRInput) + QCBOR_DECODE_MIN_MEM_POOL_SIZE); + + nCBORError = QCBORDecode_SetMemPool(&DC, Pool, 1); // Turn on copying. + if(nCBORError) { + return -1; + } + + if(CheckCSRMaps(&DC)) { + return -2; + } + + // Next parse, save pointers to a few strings, destroy original and see all is OK. + UsefulBuf_MAKE_STACK_UB(CopyOfStorage, sizeof(pValidMapEncoded) + QCBOR_DECODE_MIN_MEM_POOL_SIZE); + const UsefulBufC CopyOf = UsefulBuf_Copy(CopyOfStorage, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded)); + + QCBORDecode_Init(&DC, CopyOf, QCBOR_DECODE_MODE_NORMAL); + UsefulBuf_Set(Pool, '/'); + QCBORDecode_SetMemPool(&DC, Pool, 1); // Turn on copying. + + QCBORItem Item1, Item2, Item3, Item4; + if((nCBORError = QCBORDecode_GetNext(&DC, &Item1))) + return nCBORError; + if(Item1.uDataType != QCBOR_TYPE_MAP || + Item1.val.uCount != 3) + return -3; + if((nCBORError = QCBORDecode_GetNext(&DC, &Item1))) + return nCBORError; + if((nCBORError = QCBORDecode_GetNext(&DC, &Item2))) + return nCBORError; + if((nCBORError = QCBORDecode_GetNext(&DC, &Item3))) + return nCBORError; + if((nCBORError = QCBORDecode_GetNext(&DC, &Item4))) + return nCBORError; + + UsefulBuf_Set(CopyOfStorage, '_'); + + if(Item1.uLabelType != QCBOR_TYPE_TEXT_STRING || + Item1.uDataType != QCBOR_TYPE_INT64 || + Item1.val.int64 != 42 || + UsefulBuf_Compare(Item1.label.string, UsefulBuf_FromSZ("first integer"))) { + return -4; + } + + + if(Item2.uLabelType != QCBOR_TYPE_TEXT_STRING || + UsefulBuf_Compare(Item2.label.string, UsefulBuf_FromSZ("an array of two strings")) || + Item2.uDataType != QCBOR_TYPE_ARRAY || + Item2.val.uCount != 2) + return -5; + + if(Item3.uDataType != QCBOR_TYPE_TEXT_STRING || + UsefulBuf_Compare(Item3.val.string, UsefulBuf_FromSZ("string1"))) { + return -6; + } + + if(Item4.uDataType != QCBOR_TYPE_TEXT_STRING || + UsefulBuf_Compare(Item4.val.string, UsefulBuf_FromSZ("string2"))) { + return -7; + } + + // Next parse with a pool that is too small + UsefulBuf_MAKE_STACK_UB(SmallPool, QCBOR_DECODE_MIN_MEM_POOL_SIZE + 1); + QCBORDecode_Init(&DC, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded), QCBOR_DECODE_MODE_NORMAL); + QCBORDecode_SetMemPool(&DC, SmallPool, 1); // Turn on copying. + if((nCBORError = QCBORDecode_GetNext(&DC, &Item1))) + return -8; + if(Item1.uDataType != QCBOR_TYPE_MAP || + Item1.val.uCount != 3) { + return -9; + } + if(!(nCBORError = QCBORDecode_GetNext(&DC, &Item1))){ + if(!(nCBORError = QCBORDecode_GetNext(&DC, &Item2))) { + if(!(nCBORError = QCBORDecode_GetNext(&DC, &Item3))) { + nCBORError = QCBORDecode_GetNext(&DC, &Item4); + } + } + } + if(nCBORError != QCBOR_ERR_STRING_ALLOCATE) { + return -10; + } + + return 0; +} + +// Cheating declaration to get to the special test hook +size_t MemPoolTestHook_GetPoolSize(void *ctx); + + +int MemPoolTest(void) +{ + // Set up the decoder with a tiny bit of CBOR to parse + QCBORDecodeContext DC; + const uint8_t pMinimalCBOR[] = {0xa0}; // One empty map + QCBORDecode_Init(&DC, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pMinimalCBOR),0); + + // Set up an memory pool of 100 bytes + UsefulBuf_MAKE_STACK_UB(Pool, 100); + QCBORError nError = QCBORDecode_SetMemPool(&DC, Pool, 0); + if(nError) { + return -9; + } + + // Cheat a little to get to the string allocator object + // so we can call it directly to test it + QCBORStringAllocator *pAlloc = (QCBORStringAllocator *)DC.pStringAllocator; + // Cheat some more to know exactly the + size_t uAvailPool = MemPoolTestHook_GetPoolSize(pAlloc); + + // First test -- ask for too much in one go + UsefulBuf Allocated = (*pAlloc->fAllocate)(pAlloc->pAllocaterContext, NULL, uAvailPool+1); + if(!UsefulBuf_IsNULL(Allocated)) { + return -1; + } + + + // Re do the set up for the next test that will do a successful alloc, + // a fail, a free and then success + // This test should work on 32 and 64-bit machines if the compiler + // does the expected thing with pointer sizes for the internal + // MemPool implementation leaving 44 or 72 bytes of pool memory. + QCBORDecode_SetMemPool(&DC, Pool, 0); + + // Cheat a little to get to the string allocator object + // so we can call it directly to test it + pAlloc = (QCBORStringAllocator *)DC.pStringAllocator; + // Cheat some more to know exactly the + uAvailPool = MemPoolTestHook_GetPoolSize(pAlloc); + + Allocated = (*pAlloc->fAllocate)(pAlloc->pAllocaterContext, NULL, uAvailPool-1); + if(UsefulBuf_IsNULL(Allocated)) { // expected to succeed + return -2; + } + UsefulBuf Allocated2 = (*pAlloc->fAllocate)(pAlloc->pAllocaterContext, NULL, uAvailPool/2); + if(!UsefulBuf_IsNULL(Allocated2)) { // expected to fail + return -3; + } + (*pAlloc->fFree)(pAlloc->pAllocaterContext, Allocated.ptr); + Allocated = (*pAlloc->fAllocate)(pAlloc->pAllocaterContext, NULL, uAvailPool/2); + if(UsefulBuf_IsNULL(Allocated)) { // succeed because of the free + return -4; + } + + + // Re do set up for next test that involves a successful alloc, + // and a successful realloc and a failed realloc + QCBORDecode_SetMemPool(&DC, Pool, 0); + + // Cheat a little to get to the string allocator object + // so we can call it directly to test it + pAlloc = (QCBORStringAllocator *)DC.pStringAllocator; + Allocated = (*pAlloc->fAllocate)(pAlloc->pAllocaterContext, NULL, uAvailPool/2); + if(UsefulBuf_IsNULL(Allocated)) { // expected to succeed + return -5; + } + Allocated2 = (*pAlloc->fAllocate)(pAlloc->pAllocaterContext, Allocated.ptr, uAvailPool); + if(UsefulBuf_IsNULL(Allocated2)) { + return -6; + } + if(Allocated2.ptr != Allocated.ptr || Allocated2.len != uAvailPool) { + return -7; + } + UsefulBuf Allocated3 = (*pAlloc->fAllocate)(pAlloc->pAllocaterContext, Allocated.ptr, uAvailPool+1); + if(!UsefulBuf_IsNULL(Allocated3)) { // expected to fail + return -8; + } + + return 0; +} + diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/qcbor/test/qcbor_decode_tests.h b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/qcbor/test/qcbor_decode_tests.h new file mode 100644 index 0000000..cbd352e --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/qcbor/test/qcbor_decode_tests.h @@ -0,0 +1,230 @@ +/*============================================================================== + Copyright (c) 2016-2018, The Linux Foundation. + Copyright (c) 2018-2019, Laurence Lundblade. + All rights reserved. + SPDX-License-Identifier: BSD-3-Clause + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of The Linux Foundation nor the names of its + contributors, nor the name "Laurence Lundblade" may be used to + endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ==============================================================================*/ + +#ifndef __QCBOR__qcbort_decode_tests__ +#define __QCBOR__qcbort_decode_tests__ + +#include "qcbor.h" + + +/* + Notes: + + - All the functions in qcbor.h are called once in the aggregation of all the tests below. + + - All the types that are supported are given as input and parsed by these tests + + - There is some hostile input such as invalid lengths and CBOR too complex + and types this parser doesn't handle + + */ + + + + +/* + Parse a well-known set of integers including those around the boundaries and + make sure the expected values come out + */ +int IntegerValuesParseTest(void); + + + + + +/* + Decode a simple CBOR encoded array and make sure it returns all the correct values. + This is a decode test. + */ +int SimpleArrayTest(void); + + +/* + Make sure a maximally deep array can be parsed and that the + reported nesting level is correct. This uses test vector + of CBOR encoded data with a depth of 10. This a parse test. + */ +int ParseDeepArrayTest(void); + + +/* + See that the correct error is reported when parsing + an array of depth 11, one too large. + */ +int ParseTooDeepArrayTest(void); + + +/* + Try to parse some legit CBOR types that this parsers + doesn't support. + */ +int UnsupportedCBORDecodeTest(void); + + +/* + This takes the encoded CBOR integers used in the above test and parses + it over and over with one more byte less each time. It should fail + every time on incorrect CBOR input. This is a hostile input decode test. + */ +int ShortBufferParseTest(void); + + +/* + Same as ShortBufferParseTest, but with a different encoded CBOR input. + It is another hostile input test + */ +int ShortBufferParseTest2(void); + + +/* + Parses the somewhat complicated CBOR MAP and makes sure all the correct + values parse out. About 15 values are tested. This is a decode test. + */ +int ParseMapTest(void); + + + +int FloatValuesTest1(void); + + + +int SimpleValuesTest1(void); + + +/* + + */ +int ParseMapAsArrayTest(void); + + + +int ParseSimpleTest(void); + + + +/* + Tests a number of failure cases on bad CBOR to get the right error code + */ +int FailureTests(void); + + +/* + Parses all possible inputs that are two bytes long. Main point + is that the test doesn't crash as it doesn't evaluate the + input for correctness in any way. + + (Parsing all possible 3 byte strings takes too long on all but + very fast machines). + */ +int ComprehensiveInputTest(void); + + +/* + Parses all possible inputs that are four bytes long. Main point + is that the test doesn't crash as it doesn't evaluate the + input for correctness in any way. This runs very slow, so it + is only practical as a once-in-a-while regression test on + fast machines. + */ +int BigComprehensiveInputTest(void); + + +/* + Thest the date types -- epoch and strings + */ +int DateParseTest(void); + + +/* + Test optional tags like the CBOR magic number. + */ +int OptTagParseTest(void); + + +/* + Parse some big numbers, positive and negative + */ +int BignumParseTest(void); + + +int StringDecoderModeFailTest(void); + + +/* + Parse some nested maps + */ +int NestedMapTest(void); + + +/* + Parse maps with indefinite lengths + */ +int NestedMapTestIndefLen(void); + + +/* + Parse some maps and arrays with indefinite lengths. + Includes some error cases. + */ +int IndefiniteLengthArrayMapTest(void); + + +/* + Parse indefinite length strings. Uses + MemPool. Includes error cases. + */ +int IndefiniteLengthStringTest(void); + + +/* + Test deep nesting of indefinite length + maps and arrays including too deep. + */ +int IndefiniteLengthNestTest(void); + + +/* + Test parsing strings were all strings, not + just indefinite length strings, are + allocated. Includes error test cases. + */ +int AllocAllStringsTest(void); + + +/* + Direct test of MemPool string allocator + */ +int MemPoolTest(void); + + +#endif /* defined(__QCBOR__qcbort_decode_tests__) */ diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/qcbor/test/qcbor_encode_tests.c b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/qcbor/test/qcbor_encode_tests.c new file mode 100644 index 0000000..ca46460 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/qcbor/test/qcbor_encode_tests.c @@ -0,0 +1,2008 @@ +/*============================================================================== + Copyright (c) 2016-2018, The Linux Foundation. + Copyright (c) 2018-2019, Laurence Lundblade. + All rights reserved. + SPDX-License-Identifier: BSD-3-Clause + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of The Linux Foundation nor the names of its + contributors, nor the name "Laurence Lundblade" may be used to + endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ==============================================================================*/ + +#include "qcbor.h" +#include "qcbor_encode_tests.h" + + +/* + This is the test set for CBOR encoding. + + This is largely complete for the implemented. + + A few more things to do include: + - Add a test for counting the top level items and adding it back in with AddRaw() + - Run on some different CPUs like 32-bit and maybe even 16-bit + - Test the large array count limit + - Add the CBOR diagnostic output for every expected + + */ + +//#define PRINT_FUNCTIONS_FOR_DEBUGGINGXX + +#ifdef PRINT_FUNCTIONS_FOR_DEBUGGINGXX +#include + +// ifdef these out to not have compiler warnings +static void printencoded(const uint8_t *pEncoded, size_t nLen) +{ + size_t i; + for(i = 0; i < nLen; i++) { + uint8_t Z = pEncoded[i]; + printf("%02x ", Z); + } + printf("\n"); + + fflush(stdout); +} + + +// Do the comparison and print out where it fails +static int UsefulBuf_Compare_Print(UsefulBufC U1, UsefulBufC U2) { + size_t i; + for(i = 0; i < U1.len; i++) { + if(((uint8_t *)U1.ptr)[i] != ((uint8_t *)U2.ptr)[i]) { + printf("Position: %d Actual: 0x%x Expected: 0x%x\n", i, ((uint8_t *)U1.ptr)[i], ((uint8_t *)U2.ptr)[i]); + return 1; + } + } + return 0; + +} + +#define CheckResults(Enc, Expected) \ + UsefulBuf_Compare_Print(Enc, (UsefulBufC){Expected, sizeof(Expected)}) + +#else + +#define CheckResults(Enc, Expected) \ + UsefulBuf_Compare(Enc, (UsefulBufC){Expected, sizeof(Expected)}) + +#endif + + + +// One big buffer that is used by all the tests to encode into +// Putting it in uninitialized data is better than using a lot +// of stack. The tests should run on small devices too. +static uint8_t spBigBuf[2200]; + + + +/* + Some very minimal tests. + */ +int BasicEncodeTest() +{ + // Very simple CBOR, a map with one boolean that is true in it + QCBOREncodeContext EC; + + QCBOREncode_Init(&EC, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf)); + + QCBOREncode_OpenMap(&EC); + QCBOREncode_AddBoolToMapN(&EC, 66, true); + QCBOREncode_CloseMap(&EC); + + UsefulBufC Encoded; + if(QCBOREncode_Finish(&EC, &Encoded)) { + return -1; + } + + + // Decode it and see that is right + QCBORDecodeContext DC; + QCBORItem Item; + QCBORDecode_Init(&DC, Encoded, QCBOR_DECODE_MODE_NORMAL); + + QCBORDecode_GetNext(&DC, &Item); + if(Item.uDataType != QCBOR_TYPE_MAP) { + return -2; + } + + QCBORDecode_GetNext(&DC, &Item); + if(Item.uDataType != QCBOR_TYPE_TRUE) { + return -3; + } + + if(QCBORDecode_Finish(&DC)) { + return -4; + } + + + // Make another encoded message with the CBOR from the previous put into this one + UsefulBuf_MAKE_STACK_UB(MemoryForEncoded2, 20); + QCBOREncode_Init(&EC, MemoryForEncoded2); + QCBOREncode_OpenArray(&EC); + QCBOREncode_AddUInt64(&EC, 451); + QCBOREncode_AddEncoded(&EC, Encoded); + QCBOREncode_OpenMap(&EC); + QCBOREncode_AddEncodedToMapN(&EC, -70000, Encoded); + QCBOREncode_CloseMap(&EC); + QCBOREncode_CloseArray(&EC); + + UsefulBufC Encoded2; + if(QCBOREncode_Finish(&EC, &Encoded2)) { + return -5; + } + /* + [ // 0 1:3 + 451, // 1 1:2 + { // 1 1:2 2:1 + 66: true // 2 1:1 + }, + { // 1 1:1 2:1 + -70000: { // 2 1:1 2:1 3:1 + 66: true // 3 XXXXXX + } + } + ] + + + + 83 # array(3) + 19 01C3 # unsigned(451) + A1 # map(1) + 18 42 # unsigned(66) + F5 # primitive(21) + A1 # map(1) + 3A 0001116F # negative(69999) + A1 # map(1) + 18 42 # unsigned(66) + F5 # primitive(21) + */ + + // Decode it and see if it is OK + QCBORDecode_Init(&DC, Encoded2, QCBOR_DECODE_MODE_NORMAL); + + // 0 1:3 + QCBORDecode_GetNext(&DC, &Item); + if(Item.uDataType != QCBOR_TYPE_ARRAY || Item.val.uCount != 3) { + return -6; + } + + // 1 1:2 + QCBORDecode_GetNext(&DC, &Item); + if(Item.uDataType != QCBOR_TYPE_INT64 || Item.val.uint64 != 451) { + return -7; + } + + // 1 1:2 2:1 + QCBORDecode_GetNext(&DC, &Item); + if(Item.uDataType != QCBOR_TYPE_MAP || Item.val.uCount != 1) { + return -8; + } + + // 2 1:1 + QCBORDecode_GetNext(&DC, &Item); + if(Item.uDataType != QCBOR_TYPE_TRUE) { + return -9; + } + + // 1 1:1 2:1 + QCBORDecode_GetNext(&DC, &Item); + if(Item.uDataType != QCBOR_TYPE_MAP || Item.val.uCount != 1) { + return -10; + } + + // 2 1:1 2:1 3:1 + QCBORDecode_GetNext(&DC, &Item); + if(Item.uDataType != QCBOR_TYPE_MAP || Item.val.uCount != 1 || Item.uLabelType != QCBOR_TYPE_INT64 || Item.label.int64 != -70000) { + return -11; + } + + // 3 XXXXXX + QCBORDecode_GetNext(&DC, &Item); + if(Item.uDataType != QCBOR_TYPE_TRUE || Item.uLabelType != QCBOR_TYPE_INT64 || Item.label.int64 != 66) { + return -12; + } + + if(QCBORDecode_Finish(&DC)) { + return -13; + } + + return 0; +} + + + +static const uint8_t spExpectedEncodedAll[] = { + 0x98, 0x22, 0x66, 0x55, 0x49, 0x4e, 0x54, 0x36, 0x32, 0xd8, + 0x64, 0x1a, 0x05, 0x5d, 0x23, 0x15, 0x65, 0x49, 0x4e, 0x54, + 0x36, 0x34, 0xd8, 0x4c, 0x1b, 0x00, 0x00, 0x00, 0x12, 0x16, + 0xaf, 0x2b, 0x15, 0x00, 0x38, 0x2b, 0xa4, 0x63, 0x4c, 0x42, + 0x4c, 0x18, 0x4d, 0x23, 0x18, 0x58, 0x78, 0x1a, 0x4e, 0x45, + 0x47, 0x4c, 0x42, 0x4c, 0x54, 0x48, 0x41, 0x54, 0x20, 0x49, + 0x53, 0x20, 0x4b, 0x49, 0x4e, 0x44, 0x20, 0x4f, 0x46, 0x20, + 0x4c, 0x4f, 0x4e, 0x47, 0x3b, 0x00, 0x00, 0x02, 0x2d, 0x9a, + 0xc6, 0x94, 0x55, 0x3a, 0x05, 0xf5, 0xe0, 0xff, 0x3a, 0x2f, + 0xaf, 0x07, 0xff, 0xc1, 0x1a, 0x8e, 0x15, 0x1c, 0x8a, + 0xa3, 0x74, 0x4c, 0x6f, 0x6e, 0x67, 0x4c, 0x69, 0x76, 0x65, + 0x44, 0x65, 0x6e, 0x69, 0x73, 0x52, 0x69, 0x74, 0x63, 0x68, + 0x69, 0x65, 0xc1, 0x1a, 0x53, 0x72, 0x4e, 0x00, 0x66, 0x74, + 0x69, 0x6d, 0x65, 0x28, 0x29, 0xc1, 0x1a, 0x58, 0x0d, 0x41, + 0x72, 0x39, 0x07, 0xb0, 0xc1, 0x1a, 0x58, 0x0d, 0x3f, 0x76, + 0x42, 0xff, 0x00, 0xa3, 0x66, 0x62, 0x69, 0x6e, 0x62, 0x69, + 0x6e, 0xda, 0x00, 0x01, 0x86, 0xa0, 0x41, 0x00, 0x66, 0x62, + 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x43, 0x01, 0x02, 0x03, 0x00, + 0x44, 0x04, 0x02, 0x03, 0xfe, 0x6f, 0x62, 0x61, 0x72, 0x20, + 0x62, 0x61, 0x72, 0x20, 0x66, 0x6f, 0x6f, 0x20, 0x62, 0x61, + 0x72, 0x64, 0x6f, 0x6f, 0x66, 0x0a, 0xd8, 0x20, 0x78, 0x6b, + 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x73, 0x74, 0x61, + 0x63, 0x6b, 0x6f, 0x76, 0x65, 0x72, 0x66, 0x6c, 0x6f, 0x77, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x32, 0x38, 0x30, 0x35, 0x39, + 0x36, 0x39, 0x37, 0x2f, 0x68, 0x6f, 0x77, 0x2d, 0x64, 0x6f, + 0x2d, 0x69, 0x2d, 0x74, 0x6f, 0x67, 0x67, 0x6c, 0x65, 0x2d, + 0x62, 0x65, 0x74, 0x77, 0x65, 0x65, 0x6e, 0x2d, 0x64, 0x65, + 0x62, 0x75, 0x67, 0x2d, 0x61, 0x6e, 0x64, 0x2d, 0x72, 0x65, + 0x6c, 0x65, 0x61, 0x73, 0x65, 0x2d, 0x62, 0x75, 0x69, 0x6c, + 0x64, 0x73, 0x2d, 0x69, 0x6e, 0x2d, 0x78, 0x63, 0x6f, 0x64, + 0x65, 0x2d, 0x36, 0x2d, 0x37, 0x2d, 0x38, 0xd8, 0x22, 0x78, + 0x1c, 0x59, 0x57, 0x35, 0x35, 0x49, 0x47, 0x4e, 0x68, 0x63, + 0x6d, 0x35, 0x68, 0x62, 0x43, 0x42, 0x77, 0x62, 0x47, 0x56, + 0x68, 0x63, 0x33, 0x56, 0x79, 0x5a, 0x51, 0x3d, 0x3d, 0xd8, + 0x23, 0x67, 0x5b, 0x5e, 0x61, 0x62, 0x63, 0x5d, 0x2b, 0xd8, + 0x24, 0x79, 0x01, 0x57, 0x4d, 0x49, 0x4d, 0x45, 0x2d, 0x56, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x31, 0x2e, + 0x30, 0x0a, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, + 0x54, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x6d, 0x75, 0x6c, 0x74, + 0x69, 0x70, 0x61, 0x72, 0x74, 0x2f, 0x6d, 0x69, 0x78, 0x65, + 0x64, 0x3b, 0x0a, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72, + 0x79, 0x3d, 0x22, 0x58, 0x58, 0x58, 0x58, 0x62, 0x6f, 0x75, + 0x6e, 0x64, 0x61, 0x72, 0x79, 0x20, 0x74, 0x65, 0x78, 0x74, + 0x22, 0x0a, 0x0a, 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, + 0x20, 0x61, 0x20, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x61, + 0x72, 0x74, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x20, 0x69, 0x6e, 0x20, 0x4d, 0x49, 0x4d, 0x45, 0x20, 0x66, + 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x2e, 0x0a, 0x0a, 0x2d, 0x2d, + 0x58, 0x58, 0x58, 0x58, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61, + 0x72, 0x79, 0x20, 0x74, 0x65, 0x78, 0x74, 0x0a, 0x43, 0x6f, + 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x54, 0x79, 0x70, 0x65, + 0x3a, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x70, 0x6c, 0x61, + 0x69, 0x6e, 0x0a, 0x0a, 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, + 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x6f, 0x64, 0x79, + 0x20, 0x74, 0x65, 0x78, 0x74, 0x0a, 0x0a, 0x2d, 0x2d, 0x58, + 0x58, 0x58, 0x58, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72, + 0x79, 0x20, 0x74, 0x65, 0x78, 0x74, 0x0a, 0x43, 0x6f, 0x6e, + 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x54, 0x79, 0x70, 0x65, 0x3a, + 0x20, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x70, 0x6c, 0x61, 0x69, + 0x6e, 0x3b, 0x0a, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, + 0x2d, 0x44, 0x69, 0x73, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, + 0x6f, 0x6e, 0x3a, 0x20, 0x61, 0x74, 0x74, 0x61, 0x63, 0x68, + 0x6d, 0x65, 0x6e, 0x74, 0x3b, 0x0a, 0x66, 0x69, 0x6c, 0x65, + 0x6e, 0x61, 0x6d, 0x65, 0x3d, 0x22, 0x74, 0x65, 0x73, 0x74, + 0x2e, 0x74, 0x78, 0x74, 0x22, 0x0a, 0x0a, 0x74, 0x68, 0x69, + 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, + 0x74, 0x74, 0x61, 0x63, 0x68, 0x6d, 0x65, 0x6e, 0x74, 0x20, + 0x74, 0x65, 0x78, 0x74, 0x0a, 0x0a, 0x2d, 0x2d, 0x58, 0x58, + 0x58, 0x58, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72, 0x79, + 0x20, 0x74, 0x65, 0x78, 0x74, 0x2d, 0x2d, 0xae, 0x65, 0x23, + 0x23, 0x23, 0x23, 0x23, 0x6f, 0x66, 0x6f, 0x6f, 0x20, 0x62, + 0x61, 0x72, 0x20, 0x66, 0x6f, 0x6f, 0x20, 0x66, 0x6f, 0x6f, + 0x64, 0x5f, 0x5f, 0x5f, 0x5f, 0x67, 0x66, 0x6f, 0x6f, 0x20, + 0x62, 0x61, 0x72, 0x66, 0x28, 0x29, 0x28, 0x29, 0x28, 0x29, + 0xd9, 0x03, 0xe8, 0x6b, 0x72, 0x61, 0x62, 0x20, 0x72, 0x61, + 0x62, 0x20, 0x6f, 0x6f, 0x66, 0x16, 0x6f, 0x66, 0x6f, 0x6f, + 0x20, 0x66, 0x6f, 0x6f, 0x20, 0x66, 0x6f, 0x6f, 0x20, 0x66, + 0x6f, 0x6f, 0x62, 0x5e, 0x5e, 0x69, 0x6f, 0x6f, 0x6f, 0x6f, + 0x6f, 0x6f, 0x6f, 0x6f, 0x66, 0x18, 0x63, 0x6d, 0x66, 0x66, + 0x66, 0x66, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, + 0x66, 0x63, 0x52, 0x46, 0x43, 0xd8, 0x20, 0x78, 0x31, 0x68, + 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x74, 0x6f, 0x6f, + 0x6c, 0x73, 0x2e, 0x69, 0x65, 0x74, 0x66, 0x2e, 0x6f, 0x72, + 0x67, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x2f, 0x72, 0x66, 0x63, + 0x37, 0x30, 0x34, 0x39, 0x23, 0x73, 0x65, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x2d, 0x32, 0x2e, 0x34, 0x2e, 0x35, 0x18, 0x89, + 0xd8, 0x20, 0x6f, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, + 0x63, 0x62, 0x6f, 0x72, 0x2e, 0x6d, 0x65, 0x2f, 0x68, 0x77, + 0x68, 0x65, 0x6e, 0x69, 0x6d, 0x36, 0x34, 0xd8, 0x22, 0x6c, + 0x63, 0x47, 0x78, 0x6c, 0x59, 0x58, 0x4e, 0x31, 0x63, 0x6d, + 0x55, 0x75, 0x18, 0x40, 0xd8, 0x22, 0x68, 0x63, 0x33, 0x56, + 0x79, 0x5a, 0x53, 0x34, 0x3d, 0x64, 0x70, 0x6f, 0x70, 0x6f, + 0xd8, 0x23, 0x68, 0x31, 0x30, 0x30, 0x5c, 0x73, 0x2a, 0x6d, + 0x6b, 0x38, 0x32, 0xd8, 0x23, 0x66, 0x70, 0x65, 0x72, 0x6c, + 0x5c, 0x42, 0x63, 0x4e, 0x65, 0x64, 0xd8, 0x24, 0x79, 0x01, + 0x57, 0x4d, 0x49, 0x4d, 0x45, 0x2d, 0x56, 0x65, 0x72, 0x73, + 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x31, 0x2e, 0x30, 0x0a, 0x43, + 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x54, 0x79, 0x70, + 0x65, 0x3a, 0x20, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x61, + 0x72, 0x74, 0x2f, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x3b, 0x0a, + 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x3d, 0x22, + 0x58, 0x58, 0x58, 0x58, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61, + 0x72, 0x79, 0x20, 0x74, 0x65, 0x78, 0x74, 0x22, 0x0a, 0x0a, + 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x61, 0x20, + 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x61, 0x72, 0x74, 0x20, + 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x20, 0x69, 0x6e, + 0x20, 0x4d, 0x49, 0x4d, 0x45, 0x20, 0x66, 0x6f, 0x72, 0x6d, + 0x61, 0x74, 0x2e, 0x0a, 0x0a, 0x2d, 0x2d, 0x58, 0x58, 0x58, + 0x58, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x20, + 0x74, 0x65, 0x78, 0x74, 0x0a, 0x43, 0x6f, 0x6e, 0x74, 0x65, + 0x6e, 0x74, 0x2d, 0x54, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x74, + 0x65, 0x78, 0x74, 0x2f, 0x70, 0x6c, 0x61, 0x69, 0x6e, 0x0a, + 0x0a, 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x62, 0x6f, 0x64, 0x79, 0x20, 0x74, 0x65, + 0x78, 0x74, 0x0a, 0x0a, 0x2d, 0x2d, 0x58, 0x58, 0x58, 0x58, + 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x20, 0x74, + 0x65, 0x78, 0x74, 0x0a, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, + 0x74, 0x2d, 0x54, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x74, 0x65, + 0x78, 0x74, 0x2f, 0x70, 0x6c, 0x61, 0x69, 0x6e, 0x3b, 0x0a, + 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x44, 0x69, + 0x73, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, + 0x20, 0x61, 0x74, 0x74, 0x61, 0x63, 0x68, 0x6d, 0x65, 0x6e, + 0x74, 0x3b, 0x0a, 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, + 0x65, 0x3d, 0x22, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x74, 0x78, + 0x74, 0x22, 0x0a, 0x0a, 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, + 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, 0x74, 0x74, 0x61, + 0x63, 0x68, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x74, 0x65, 0x78, + 0x74, 0x0a, 0x0a, 0x2d, 0x2d, 0x58, 0x58, 0x58, 0x58, 0x62, + 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x20, 0x74, 0x65, + 0x78, 0x74, 0x2d, 0x2d, 0x0a, 0xd8, 0x24, 0x79, 0x01, 0x57, + 0x4d, 0x49, 0x4d, 0x45, 0x2d, 0x56, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x3a, 0x20, 0x31, 0x2e, 0x30, 0x0a, 0x43, 0x6f, + 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x54, 0x79, 0x70, 0x65, + 0x3a, 0x20, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x61, 0x72, + 0x74, 0x2f, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x3b, 0x0a, 0x62, + 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x3d, 0x22, 0x58, + 0x58, 0x58, 0x58, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72, + 0x79, 0x20, 0x74, 0x65, 0x78, 0x74, 0x22, 0x0a, 0x0a, 0x54, + 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x61, 0x20, 0x6d, + 0x75, 0x6c, 0x74, 0x69, 0x70, 0x61, 0x72, 0x74, 0x20, 0x6d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x20, 0x69, 0x6e, 0x20, + 0x4d, 0x49, 0x4d, 0x45, 0x20, 0x66, 0x6f, 0x72, 0x6d, 0x61, + 0x74, 0x2e, 0x0a, 0x0a, 0x2d, 0x2d, 0x58, 0x58, 0x58, 0x58, + 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x20, 0x74, + 0x65, 0x78, 0x74, 0x0a, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, + 0x74, 0x2d, 0x54, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x74, 0x65, + 0x78, 0x74, 0x2f, 0x70, 0x6c, 0x61, 0x69, 0x6e, 0x0a, 0x0a, + 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x62, 0x6f, 0x64, 0x79, 0x20, 0x74, 0x65, 0x78, + 0x74, 0x0a, 0x0a, 0x2d, 0x2d, 0x58, 0x58, 0x58, 0x58, 0x62, + 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x20, 0x74, 0x65, + 0x78, 0x74, 0x0a, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, + 0x2d, 0x54, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x74, 0x65, 0x78, + 0x74, 0x2f, 0x70, 0x6c, 0x61, 0x69, 0x6e, 0x3b, 0x0a, 0x43, + 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x44, 0x69, 0x73, + 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, + 0x61, 0x74, 0x74, 0x61, 0x63, 0x68, 0x6d, 0x65, 0x6e, 0x74, + 0x3b, 0x0a, 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65, + 0x3d, 0x22, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x74, 0x78, 0x74, + 0x22, 0x0a, 0x0a, 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, 0x74, 0x74, 0x61, 0x63, + 0x68, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x74, 0x65, 0x78, 0x74, + 0x0a, 0x0a, 0x2d, 0x2d, 0x58, 0x58, 0x58, 0x58, 0x62, 0x6f, + 0x75, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x20, 0x74, 0x65, 0x78, + 0x74, 0x2d, 0x2d, 0xc0, 0x74, 0x32, 0x30, 0x30, 0x33, 0x2d, + 0x31, 0x32, 0x2d, 0x31, 0x33, 0x54, 0x31, 0x38, 0x3a, 0x33, + 0x30, 0x3a, 0x30, 0x32, 0x5a, 0xa2, 0x68, 0x42, 0x65, 0x64, + 0x20, 0x74, 0x69, 0x6d, 0x65, 0xc0, 0x78, 0x1c, 0x32, 0x30, + 0x30, 0x33, 0x2d, 0x31, 0x32, 0x2d, 0x31, 0x33, 0x54, 0x31, + 0x38, 0x3a, 0x33, 0x30, 0x3a, 0x30, 0x32, 0x2e, 0x32, 0x35, + 0x2b, 0x30, 0x31, 0x3a, 0x30, 0x30, 0x18, 0x58, 0xc0, 0x78, + 0x1c, 0x32, 0x30, 0x30, 0x33, 0x2d, 0x31, 0x32, 0x2d, 0x31, + 0x33, 0x54, 0x31, 0x38, 0x3a, 0x33, 0x30, 0x3a, 0x30, 0x32, + 0x2e, 0x32, 0x35, 0x2b, 0x30, 0x31, 0x3a, 0x30, 0x30, 0xf7, + 0xa3, 0x64, 0x64, 0x61, 0x72, 0x65, 0xd8, 0x42, 0xf5, 0x62, + 0x75, 0x75, 0xf4, 0x1a, 0x00, 0x0b, 0x41, 0x62, 0xf6, 0x80, + 0xa3, 0x78, 0x1c, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x20, 0x61, + 0x6e, 0x64, 0x20, 0x74, 0x61, 0x67, 0x67, 0x65, 0x64, 0x20, + 0x65, 0x6d, 0x70, 0x74, 0x79, 0x20, 0x61, 0x72, 0x72, 0x61, + 0x79, 0xd9, 0x04, 0x45, 0x80, 0x65, 0x61, 0x6c, 0x61, 0x62, + 0x6c, 0x80, 0x18, 0x2a, 0x80, 0xa1, 0x68, 0x69, 0x6e, 0x20, + 0x61, 0x20, 0x6d, 0x61, 0x70, 0xa1, 0x19, 0x15, 0xb4, 0xa1, + 0x6e, 0x69, 0x6e, 0x20, 0x61, 0x20, 0x69, 0x6e, 0x20, 0x61, + 0x20, 0x69, 0x6e, 0x20, 0x61, 0xd9, 0x23, 0x7f, 0xa0, 0xa5, + 0x62, 0x73, 0x31, 0xd8, 0x58, 0xf8, 0xff, 0x62, 0x73, 0x32, + 0xe0, 0x62, 0x73, 0x33, 0xd8, 0x58, 0xf8, 0x21, 0x1a, 0x05, + 0x44, 0x8c, 0x06, 0xd8, 0x58, 0xf8, 0xff, 0x18, 0x59, 0xd8, + 0x58, 0xf3, 0xd8, 0x25, 0x50, 0x53, 0x4d, 0x41, 0x52, 0x54, + 0x43, 0x53, 0x4c, 0x54, 0x54, 0x43, 0x46, 0x49, 0x43, 0x41, + 0x32, 0xa2, 0x64, 0x55, 0x55, 0x55, 0x55, 0xd8, 0x25, 0x50, + 0x53, 0x4d, 0x41, 0x52, 0x54, 0x43, 0x53, 0x4c, 0x54, 0x54, + 0x43, 0x46, 0x49, 0x43, 0x41, 0x32, 0x18, 0x63, 0xd8, 0x25, + 0x50, 0x53, 0x4d, 0x41, 0x52, 0x54, 0x43, 0x53, 0x4c, 0x54, + 0x54, 0x43, 0x46, 0x49, 0x43, 0x41, 0x32, 0xf5, 0xf4, 0xa2, + 0x71, 0x47, 0x65, 0x6f, 0x72, 0x67, 0x65, 0x20, 0x69, 0x73, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x6d, 0x61, 0x6e, 0xf5, 0x19, + 0x10, 0x41, 0xf5, 0xC2, 0x49, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xC3, 0x49, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xA4, 0x63, 0x42, 0x4E, 0x2B, + 0xC2, 0x49, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x18, 0x40, 0xC2, 0x49, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x63, 0x42, 0x4E, 0x2D, 0xC3, 0x49, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, + 0x3F, 0xC3, 0x49, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00 +}; + + +static const char *szMIME = "\ +MIME-Version: 1.0\n\ +Content-Type: multipart/mixed;\n\ +boundary=\"XXXXboundary text\"\n\ +\n\ +This is a multipart message in MIME format.\n\ +\n\ +--XXXXboundary text\n\ +Content-Type: text/plain\n\ +\n\ +this is the body text\n\ +\n\ +--XXXXboundary text\n\ +Content-Type: text/plain;\n\ +Content-Disposition: attachment;\n\ +filename=\"test.txt\"\n\ +\n\ +this is the attachment text\n\ +\n\ +--XXXXboundary text--"; + + +int AllAddMethodsTest() +{ + // TODO: this test should be broken down into several so it is more managable. Tags and labels could be more sensible + QCBOREncodeContext ECtx; + int nReturn = 0; + + QCBOREncode_Init(&ECtx, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf)); + + QCBOREncode_OpenArray(&ECtx); + + // Some ints that are tagged and have strings preceeding them (not labels becase it is not a map) + QCBOREncode_AddSZString(&ECtx, "UINT62"); + QCBOREncode_AddTag(&ECtx, 100); + QCBOREncode_AddUInt64(&ECtx, 89989909); + QCBOREncode_AddSZString(&ECtx, "INT64"); + QCBOREncode_AddTag(&ECtx, 76); + QCBOREncode_AddInt64(&ECtx, 77689989909); + QCBOREncode_AddUInt64(&ECtx,0); + QCBOREncode_AddInt64(&ECtx, -44); + + // ints that go in maps + QCBOREncode_OpenMap(&ECtx); + QCBOREncode_AddUInt64ToMap(&ECtx, "LBL", 77); + QCBOREncode_AddUInt64ToMapN(&ECtx, -4, 88); + QCBOREncode_AddInt64ToMap(&ECtx, "NEGLBLTHAT IS KIND OF LONG", -2394893489238); + QCBOREncode_AddInt64ToMapN(&ECtx, -100000000, -800000000); + QCBOREncode_CloseMap(&ECtx); + + // Epoch Date + QCBOREncode_AddDateEpoch(&ECtx, 2383748234); + + // Epoch date with labels + QCBOREncode_OpenMap(&ECtx); + QCBOREncode_AddDateEpochToMap(&ECtx, "LongLiveDenisRitchie", 1400000000); + QCBOREncode_AddDateEpochToMap(&ECtx, "time()", 1477263730); + QCBOREncode_AddDateEpochToMapN(&ECtx, -1969, 1477263222); + QCBOREncode_CloseMap(&ECtx); + + // Binary blobs + QCBOREncode_AddBytes(&ECtx, ((UsefulBufC) {(uint8_t []){0xff, 0x00}, 2})); + + // binary blobs in maps + QCBOREncode_OpenMap(&ECtx); + QCBOREncode_AddSZString(&ECtx, "binbin"); + QCBOREncode_AddTag(&ECtx, 100000); + QCBOREncode_AddBytes(&ECtx, ((UsefulBufC) {(uint8_t []){0x00}, 1})); + QCBOREncode_AddBytesToMap(&ECtx, "blabel", ((UsefulBufC) {(uint8_t []){0x01, 0x02, 0x03}, 3})); + QCBOREncode_AddBytesToMapN(&ECtx, 0, ((UsefulBufC){(uint8_t []){0x04, 0x02, 0x03, 0xfe}, 4})); + QCBOREncode_CloseMap(&ECtx); + + // text blobs + QCBOREncode_AddText(&ECtx, UsefulBuf_FROM_SZ_LITERAL("bar bar foo bar")); + QCBOREncode_AddSZString(&ECtx, "oof\n"); + QCBOREncode_AddURI(&ECtx, UsefulBuf_FROM_SZ_LITERAL("http://stackoverflow.com/questions/28059697/how-do-i-toggle-between-debug-and-release-builds-in-xcode-6-7-8")); + QCBOREncode_AddB64Text(&ECtx, UsefulBuf_FROM_SZ_LITERAL("YW55IGNhcm5hbCBwbGVhc3VyZQ==")); + QCBOREncode_AddRegex(&ECtx, UsefulBuf_FROM_SZ_LITERAL("[^abc]+")); + QCBOREncode_AddMIMEData(&ECtx, UsefulBuf_FromSZ(szMIME)); + + // text blobs in maps + QCBOREncode_OpenMap(&ECtx); + QCBOREncode_AddTextToMap(&ECtx, "#####", UsefulBuf_FROM_SZ_LITERAL("foo bar foo foo")); + QCBOREncode_AddTextToMap(&ECtx, "____", UsefulBuf_FROM_SZ_LITERAL("foo bar")); + QCBOREncode_AddSZString(&ECtx, "()()()"); + QCBOREncode_AddTag(&ECtx, 1000); + QCBOREncode_AddSZString(&ECtx, "rab rab oof"); + QCBOREncode_AddTextToMapN(&ECtx,22, UsefulBuf_FROM_SZ_LITERAL("foo foo foo foo")); + QCBOREncode_AddSZStringToMap(&ECtx, "^^", "oooooooof"); + QCBOREncode_AddSZStringToMapN(&ECtx, 99, "ffffoooooooof"); + QCBOREncode_AddURIToMap(&ECtx, "RFC", UsefulBuf_FROM_SZ_LITERAL("https://tools.ietf.org/html/rfc7049#section-2.4.5")); + QCBOREncode_AddURIToMapN(&ECtx, 0x89, UsefulBuf_FROM_SZ_LITERAL("http://cbor.me/")); + QCBOREncode_AddB64TextToMap(&ECtx, "whenim64", UsefulBuf_FROM_SZ_LITERAL("cGxlYXN1cmUu")); + QCBOREncode_AddB64TextToMapN(&ECtx, 64, UsefulBuf_FROM_SZ_LITERAL("c3VyZS4=")); + QCBOREncode_AddRegexToMap(&ECtx, "popo", UsefulBuf_FROM_SZ_LITERAL("100\\s*mk")); // x code string literal bug + QCBOREncode_AddRegexToMapN(&ECtx, -51, UsefulBuf_FROM_SZ_LITERAL("perl\\B")); // x code string literal bug + QCBOREncode_AddMIMEDataToMap(&ECtx, "Ned", UsefulBuf_FromSZ(szMIME)); + QCBOREncode_AddMIMEDataToMapN(&ECtx, 10, UsefulBuf_FromSZ(szMIME)); + QCBOREncode_CloseMap(&ECtx); + + // Date strings + QCBOREncode_AddDateString(&ECtx, "2003-12-13T18:30:02Z"); + QCBOREncode_OpenMap(&ECtx); + QCBOREncode_AddDateStringToMap(&ECtx, "Bed time", "2003-12-13T18:30:02.25+01:00"); + QCBOREncode_AddDateStringToMapN(&ECtx, 88, "2003-12-13T18:30:02.25+01:00"); + QCBOREncode_CloseMap(&ECtx); + + // true / false ... + QCBOREncode_AddSimple(&ECtx, CBOR_SIMPLEV_UNDEF); + QCBOREncode_OpenMap(&ECtx); + QCBOREncode_AddSZString(&ECtx, "dare"); + QCBOREncode_AddTag(&ECtx, 66); + QCBOREncode_AddBool(&ECtx, true); + QCBOREncode_AddBoolToMap(&ECtx, "uu", false); + QCBOREncode_AddSimpleToMapN(&ECtx, 737634, CBOR_SIMPLEV_NULL); + QCBOREncode_CloseMap(&ECtx); + + // opening an array + QCBOREncode_OpenArray(&ECtx); + QCBOREncode_CloseArray(&ECtx); + + // opening arrays in a map + QCBOREncode_OpenMap(&ECtx); + QCBOREncode_AddSZString(&ECtx, "label and tagged empty array"); + QCBOREncode_AddTag(&ECtx, 1093); + QCBOREncode_OpenArray(&ECtx); + QCBOREncode_CloseArray(&ECtx); + QCBOREncode_OpenArrayInMap(&ECtx, "alabl"); + QCBOREncode_CloseArray(&ECtx); + QCBOREncode_OpenArrayInMapN(&ECtx, 42); + QCBOREncode_CloseArray(&ECtx); + QCBOREncode_CloseMap(&ECtx); + + // opening maps with labels and tagging + QCBOREncode_OpenMap(&ECtx); + QCBOREncode_OpenMapInMap(&ECtx, "in a map"); + QCBOREncode_OpenMapInMapN(&ECtx, 5556); + QCBOREncode_AddSZString(&ECtx, "in a in a in a"); + QCBOREncode_AddTag(&ECtx, 9087); + QCBOREncode_OpenMap(&ECtx); + QCBOREncode_CloseMap(&ECtx); + QCBOREncode_CloseMap(&ECtx); + QCBOREncode_CloseMap(&ECtx); + QCBOREncode_CloseMap(&ECtx); + + + // Extended simple values (these are not standard...) + QCBOREncode_OpenMap(&ECtx); + QCBOREncode_AddSZString(&ECtx, "s1"); + QCBOREncode_AddTag(&ECtx, 88); + QCBOREncode_AddSimple(&ECtx, 255); + QCBOREncode_AddSimpleToMap(&ECtx, "s2", 0); + QCBOREncode_AddSZString(&ECtx, "s3"); + QCBOREncode_AddTag(&ECtx, 88); + QCBOREncode_AddSimple(&ECtx, 33); + QCBOREncode_AddInt64(&ECtx, 88378374); // label before tag + QCBOREncode_AddTag(&ECtx, 88); + QCBOREncode_AddSimple(&ECtx, 255); + QCBOREncode_AddInt64(&ECtx, 89); // label before tag + QCBOREncode_AddTag(&ECtx, 88); + QCBOREncode_AddSimple(&ECtx, 19); + QCBOREncode_CloseMap(&ECtx); + + // UUIDs + static const uint8_t ppppUUID[] = {0x53, 0x4D, 0x41, 0x52, 0x54, 0x43, 0x53, 0x4C, 0x54, 0x54, 0x43, 0x46, 0x49, 0x43, 0x41, 0x32}; + const UsefulBufC XXUUID = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(ppppUUID); + QCBOREncode_AddBinaryUUID(&ECtx, XXUUID); + QCBOREncode_OpenMap(&ECtx); + QCBOREncode_AddBinaryUUIDToMap(&ECtx, "UUUU", XXUUID); + QCBOREncode_AddBinaryUUIDToMapN(&ECtx, 99, XXUUID); + QCBOREncode_CloseMap(&ECtx); + + // Bool + QCBOREncode_AddBool(&ECtx, true); + QCBOREncode_AddBool(&ECtx, false); + QCBOREncode_OpenMap(&ECtx); + QCBOREncode_AddBoolToMap(&ECtx, "George is the man", true); + QCBOREncode_AddBoolToMapN(&ECtx, 010101, true); + QCBOREncode_CloseMap(&ECtx); + + + static const uint8_t pBignum[] = {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + const UsefulBufC BIGNUM = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pBignum); + QCBOREncode_AddPositiveBignum(&ECtx, BIGNUM); + QCBOREncode_AddNegativeBignum(&ECtx, BIGNUM); + QCBOREncode_OpenMap(&ECtx); + QCBOREncode_AddPositiveBignumToMap(&ECtx, "BN+", BIGNUM); + QCBOREncode_AddPositiveBignumToMapN(&ECtx, 64, BIGNUM); + QCBOREncode_AddNegativeBignumToMap(&ECtx, "BN-", BIGNUM); + QCBOREncode_AddNegativeBignumToMapN(&ECtx, -64, BIGNUM); + QCBOREncode_CloseMap(&ECtx); + + QCBOREncode_CloseArray(&ECtx); + + UsefulBufC Enc; + + if(QCBOREncode_Finish(&ECtx, &Enc)) { + nReturn = -1; + goto Done; + } + + if(CheckResults(Enc, spExpectedEncodedAll)) + nReturn = -2; + +Done: + return nReturn; +} + +/* + 98 2F # array(47) + 3B 7FFFFFFFFFFFFFFF # negative(9223372036854775807) + 3B 0000000100000000 # negative(4294967296) + 3A FFFFFFFF # negative(4294967295) + 3A FFFFFFFE # negative(4294967294) + 3A FFFFFFFD # negative(4294967293) + 3A 7FFFFFFF # negative(2147483647) + 3A 7FFFFFFE # negative(2147483646) + 3A 00010001 # negative(65537) + 3A 00010000 # negative(65536) + 39 FFFF # negative(65535) + 39 FFFE # negative(65534) + 39 FFFD # negative(65533) + 39 0100 # negative(256) + 38 FF # negative(255) + 38 FE # negative(254) + 38 FD # negative(253) + 38 18 # negative(24) + 37 # negative(23) + 36 # negative(22) + 20 # negative(0) + 00 # unsigned(0) + 00 # unsigned(0) + 01 # unsigned(1) + 16 # unsigned(22) + 17 # unsigned(23) + 18 18 # unsigned(24) + 18 19 # unsigned(25) + 18 1A # unsigned(26) + 18 FE # unsigned(254) + 18 FF # unsigned(255) + 19 0100 # unsigned(256) + 19 0101 # unsigned(257) + 19 FFFE # unsigned(65534) + 19 FFFF # unsigned(65535) + 1A 00010000 # unsigned(65536) + 1A 00010001 # unsigned(65537) + 1A 00010002 # unsigned(65538) + 1A 7FFFFFFF # unsigned(2147483647) + 1A 7FFFFFFF # unsigned(2147483647) + 1A 80000000 # unsigned(2147483648) + 1A 80000001 # unsigned(2147483649) + 1A FFFFFFFE # unsigned(4294967294) + 1A FFFFFFFF # unsigned(4294967295) + 1B 0000000100000000 # unsigned(4294967296) + 1B 0000000100000001 # unsigned(4294967297) + 1B 7FFFFFFFFFFFFFFF # unsigned(9223372036854775807) + 1B FFFFFFFFFFFFFFFF # unsigned(18446744073709551615) + */ +static const uint8_t spExpectedEncodedInts[] = { + 0x98, 0x2f, 0x3b, 0x7f, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x3b, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x3a, 0xff, 0xff, 0xff, + 0xff, 0x3a, 0xff, 0xff, 0xff, 0xfe, 0x3a, 0xff, + 0xff, 0xff, 0xfd, 0x3a, 0x7f, 0xff, 0xff, 0xff, + 0x3a, 0x7f, 0xff, 0xff, 0xfe, 0x3a, 0x00, 0x01, + 0x00, 0x01, 0x3a, 0x00, 0x01, 0x00, 0x00, 0x39, + 0xff, 0xff, 0x39, 0xff, 0xfe, 0x39, 0xff, 0xfd, + 0x39, 0x01, 0x00, 0x38, 0xff, 0x38, 0xfe, 0x38, + 0xfd, 0x38, 0x18, 0x37, 0x36, 0x20, 0x00, 0x00, + 0x01, 0x16, 0x17, 0x18, 0x18, 0x18, 0x19, 0x18, + 0x1a, 0x18, 0xfe, 0x18, 0xff, 0x19, 0x01, 0x00, + 0x19, 0x01, 0x01, 0x19, 0xff, 0xfe, 0x19, 0xff, + 0xff, 0x1a, 0x00, 0x01, 0x00, 0x00, 0x1a, 0x00, + 0x01, 0x00, 0x01, 0x1a, 0x00, 0x01, 0x00, 0x02, + 0x1a, 0x7f, 0xff, 0xff, 0xff, 0x1a, 0x7f, 0xff, + 0xff, 0xff, 0x1a, 0x80, 0x00, 0x00, 0x00, 0x1a, + 0x80, 0x00, 0x00, 0x01, 0x1a, 0xff, 0xff, 0xff, + 0xfe, 0x1a, 0xff, 0xff, 0xff, 0xff, 0x1b, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x1b, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, + 0x1b, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x1b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff}; + +/* + + Test the generation of integers. This also ends up testing + encoding of all the different lengths. It encodes integers + of many lengths and values, especially around the boundaries + for different types of integers. It compares the output + to expected values generated from http://cbor.me. + + */ +int IntegerValuesTest1() +{ + QCBOREncodeContext ECtx; + int nReturn = 0; + + QCBOREncode_Init(&ECtx, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf)); + QCBOREncode_OpenArray(&ECtx); + + QCBOREncode_AddInt64(&ECtx, -9223372036854775807LL - 1); + QCBOREncode_AddInt64(&ECtx, -4294967297); + QCBOREncode_AddInt64(&ECtx, -4294967296); + QCBOREncode_AddInt64(&ECtx, -4294967295); + QCBOREncode_AddInt64(&ECtx, -4294967294); + QCBOREncode_AddInt64(&ECtx, -2147483648); + QCBOREncode_AddInt64(&ECtx, -2147483647); + QCBOREncode_AddInt64(&ECtx, -65538); + QCBOREncode_AddInt64(&ECtx, -65537); + QCBOREncode_AddInt64(&ECtx, -65536); + QCBOREncode_AddInt64(&ECtx, -65535); + QCBOREncode_AddInt64(&ECtx, -65534); + QCBOREncode_AddInt64(&ECtx, -257); + QCBOREncode_AddInt64(&ECtx, -256); + QCBOREncode_AddInt64(&ECtx, -255); + QCBOREncode_AddInt64(&ECtx, -254); + QCBOREncode_AddInt64(&ECtx, -25); + QCBOREncode_AddInt64(&ECtx, -24); + QCBOREncode_AddInt64(&ECtx, -23); + QCBOREncode_AddInt64(&ECtx, -1); + QCBOREncode_AddInt64(&ECtx, 0); + QCBOREncode_AddUInt64(&ECtx, 0ULL); + QCBOREncode_AddInt64(&ECtx, 1); + QCBOREncode_AddInt64(&ECtx, 22); + QCBOREncode_AddInt64(&ECtx, 23); + QCBOREncode_AddInt64(&ECtx, 24); + QCBOREncode_AddInt64(&ECtx, 25); + QCBOREncode_AddInt64(&ECtx, 26); + QCBOREncode_AddInt64(&ECtx, 254); + QCBOREncode_AddInt64(&ECtx, 255); + QCBOREncode_AddInt64(&ECtx, 256); + QCBOREncode_AddInt64(&ECtx, 257); + QCBOREncode_AddInt64(&ECtx, 65534); + QCBOREncode_AddInt64(&ECtx, 65535); + QCBOREncode_AddInt64(&ECtx, 65536); + QCBOREncode_AddInt64(&ECtx, 65537); + QCBOREncode_AddInt64(&ECtx, 65538); + QCBOREncode_AddInt64(&ECtx, 2147483647); + QCBOREncode_AddInt64(&ECtx, 2147483647); + QCBOREncode_AddInt64(&ECtx, 2147483648); + QCBOREncode_AddInt64(&ECtx, 2147483649); + QCBOREncode_AddInt64(&ECtx, 4294967294); + QCBOREncode_AddInt64(&ECtx, 4294967295); + QCBOREncode_AddInt64(&ECtx, 4294967296); + QCBOREncode_AddInt64(&ECtx, 4294967297); + QCBOREncode_AddInt64(&ECtx, 9223372036854775807LL); + QCBOREncode_AddUInt64(&ECtx, 18446744073709551615ULL); + + QCBOREncode_CloseArray(&ECtx); + + UsefulBufC Enc; + if(QCBOREncode_Finish(&ECtx, &Enc)) { + nReturn = -1; + } + + if(CheckResults(Enc, spExpectedEncodedInts)) + return -2; + + return(nReturn); +} + + +/* + 85 # array(5) + F5 # primitive(21) + F4 # primitive(20) + F6 # primitive(22) + F7 # primitive(23) + A1 # map(1) + 65 # text(5) + 554E446566 # "UNDef" + F7 # primitive(23) + */ +static const uint8_t spExpectedEncodedSimple[] = { + 0x85, 0xf5, 0xf4, 0xf6, 0xf7, 0xa1, 0x65, 0x55, 0x4e, 0x44, 0x65, 0x66, 0xf7}; + +int SimpleValuesTest1() +{ + QCBOREncodeContext ECtx; + int nReturn = 0; + + QCBOREncode_Init(&ECtx, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf)); + QCBOREncode_OpenArray(&ECtx); + + QCBOREncode_AddSimple(&ECtx, CBOR_SIMPLEV_TRUE); + QCBOREncode_AddSimple(&ECtx, CBOR_SIMPLEV_FALSE); + QCBOREncode_AddSimple(&ECtx, CBOR_SIMPLEV_NULL); + QCBOREncode_AddSimple(&ECtx, CBOR_SIMPLEV_UNDEF); + + QCBOREncode_OpenMap(&ECtx); + + QCBOREncode_AddSimpleToMap(&ECtx, "UNDef", CBOR_SIMPLEV_UNDEF); + QCBOREncode_CloseMap(&ECtx); + + QCBOREncode_CloseArray(&ECtx); + + UsefulBufC ECBOR; + if(QCBOREncode_Finish(&ECtx, &ECBOR)) { + nReturn = -1; + } + + if(CheckResults(ECBOR, spExpectedEncodedSimple)) + return -2; + + return(nReturn); +} + + +/* + 83 # array(3) + C0 # tag(0) + 74 # text(20) + 323031332D30332D32315432303A30343A30305A # "2013-03-21T20:04:00Z" + C1 # tag(1) + 1A 514B67B0 # unsigned(1363896240) + A2 # map(2) + 78 19 # text(25) + 53616D706C6520446174652066726F6D205246432033333339 # "Sample Date from RFC 3339" + C0 # tag(0) + 77 # text(23) + 313938352D30342D31325432333A32303A35302E35325A # "1985-04-12T23:20:50.52Z" + 62 # text(2) + 5344 # "SD" + C1 # tag(1) + 19 03E7 # unsigned(999) + */ +static const uint8_t spExpectedEncodedDates[] = { + 0x83, 0xc0, 0x74, 0x32, 0x30, 0x31, 0x33, 0x2d, 0x30, 0x33, + 0x2d, 0x32, 0x31, 0x54, 0x32, 0x30, 0x3a, 0x30, 0x34, 0x3a, + 0x30, 0x30, 0x5a, 0xc1, 0x1a, 0x51, 0x4b, 0x67, 0xb0, 0xa2, + 0x78, 0x19, 0x53, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x20, 0x44, + 0x61, 0x74, 0x65, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x52, + 0x46, 0x43, 0x20, 0x33, 0x33, 0x33, 0x39, 0xc0, 0x77, 0x31, + 0x39, 0x38, 0x35, 0x2d, 0x30, 0x34, 0x2d, 0x31, 0x32, 0x54, + 0x32, 0x33, 0x3a, 0x32, 0x30, 0x3a, 0x35, 0x30, 0x2e, 0x35, + 0x32, 0x5a, 0x62, 0x53, 0x44, 0xc1, 0x19, 0x03, 0xe7 +}; + +int EncodeDateTest() +{ + QCBOREncodeContext ECtx; + int nReturn = 0; + + QCBOREncode_Init(&ECtx, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf)); + + QCBOREncode_OpenArray(&ECtx); + + + QCBOREncode_AddDateString(&ECtx, "2013-03-21T20:04:00Z"); // from CBOR RFC + QCBOREncode_AddDateEpoch(&ECtx, 1363896240); // from CBOR RFC + + + QCBOREncode_OpenMap(&ECtx); + + QCBOREncode_AddDateStringToMap(&ECtx, "Sample Date from RFC 3339", "1985-04-12T23:20:50.52Z"); + + QCBOREncode_AddDateEpochToMap(&ECtx, "SD", 999); + + QCBOREncode_CloseMap(&ECtx); + + QCBOREncode_CloseArray(&ECtx); + + UsefulBufC ECBOR; + + if(QCBOREncode_Finish(&ECtx, &ECBOR)) { + nReturn = -1; + } + + if(CheckResults(ECBOR, spExpectedEncodedDates)) + return -2; + + return(nReturn); +} + + +int ArrayNestingTest1() +{ + QCBOREncodeContext ECtx; + int i; + int nReturn = 0; + + QCBOREncode_Init(&ECtx, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf)); + for(i = QCBOR_MAX_ARRAY_NESTING; i; i--) { + QCBOREncode_OpenArray(&ECtx); + } + for(i = QCBOR_MAX_ARRAY_NESTING; i; i--) { + QCBOREncode_CloseArray(&ECtx); + } + UsefulBufC Encoded; + if(QCBOREncode_Finish(&ECtx, &Encoded)) { + nReturn = -1; + } + + return(nReturn); +} + + + +int ArrayNestingTest2() +{ + QCBOREncodeContext ECtx; + int i; + int nReturn = 0; + + QCBOREncode_Init(&ECtx, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf)); + for(i = QCBOR_MAX_ARRAY_NESTING+1; i; i--) { + QCBOREncode_OpenArray(&ECtx); + } + for(i = QCBOR_MAX_ARRAY_NESTING; i; i--) { + QCBOREncode_CloseArray(&ECtx); + } + + UsefulBufC Encoded; + if(QCBOREncode_Finish(&ECtx, &Encoded) != QCBOR_ERR_ARRAY_NESTING_TOO_DEEP) { + nReturn = -1; + } + + return(nReturn); +} + + + +int ArrayNestingTest3() +{ + QCBOREncodeContext ECtx; + int i; + int nReturn = 0; + + QCBOREncode_Init(&ECtx, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf)); + for(i = QCBOR_MAX_ARRAY_NESTING; i; i--) { + QCBOREncode_OpenArray(&ECtx); + } + for(i = QCBOR_MAX_ARRAY_NESTING+1 ; i; i--) { + QCBOREncode_CloseArray(&ECtx); + } + UsefulBufC Encoded; + if(QCBOREncode_Finish(&ECtx, &Encoded) != QCBOR_ERR_TOO_MANY_CLOSES) { + nReturn = -1; + } + + return(nReturn); +} + + +/* + 81 # array(1) + 81 # array(1) + 81 # array(1) + 81 # array(1) + 80 # array(0) +*/ +static const uint8_t spFiveArrarys[] = {0x81, 0x81, 0x81, 0x81, 0x80}; + +// Validated at http://cbor.me and by manually examining its output +/* + 82 # array(2) + 81 # array(1) + 81 # array(1) + 81 # array(1) + 81 # array(1) + 80 # array(0) + 98 2F # array(47) + 3B 7FFFFFFFFFFFFFFF # negative(9223372036854775807) + 3B 0000000100000000 # negative(4294967296) + 3A FFFFFFFF # negative(4294967295) + 3A FFFFFFFE # negative(4294967294) + 3A FFFFFFFD # negative(4294967293) + 3A 7FFFFFFF # negative(2147483647) + 3A 7FFFFFFE # negative(2147483646) + 3A 00010001 # negative(65537) + 3A 00010000 # negative(65536) + 39 FFFF # negative(65535) + 39 FFFE # negative(65534) + 39 FFFD # negative(65533) + 39 0100 # negative(256) + 38 FF # negative(255) + 38 FE # negative(254) + 38 FD # negative(253) + 38 18 # negative(24) + 37 # negative(23) + 36 # negative(22) + 20 # negative(0) + 00 # unsigned(0) + 00 # unsigned(0) + 01 # unsigned(1) + 16 # unsigned(22) + 17 # unsigned(23) + 18 18 # unsigned(24) + 18 19 # unsigned(25) + 18 1A # unsigned(26) + 18 FE # unsigned(254) + 18 FF # unsigned(255) + 19 0100 # unsigned(256) + 19 0101 # unsigned(257) + 19 FFFE # unsigned(65534) + 19 FFFF # unsigned(65535) + 1A 00010000 # unsigned(65536) + 1A 00010001 # unsigned(65537) + 1A 00010002 # unsigned(65538) + 1A 7FFFFFFF # unsigned(2147483647) + 1A 7FFFFFFF # unsigned(2147483647) + 1A 80000000 # unsigned(2147483648) + 1A 80000001 # unsigned(2147483649) + 1A FFFFFFFE # unsigned(4294967294) + 1A FFFFFFFF # unsigned(4294967295) + 1B 0000000100000000 # unsigned(4294967296) + 1B 0000000100000001 # unsigned(4294967297) + 1B 7FFFFFFFFFFFFFFF # unsigned(9223372036854775807) + 1B FFFFFFFFFFFFFFFF # unsigned(18446744073709551615) + */ +static const uint8_t spEncodeRawExpected[] = { + 0x82, 0x81, 0x81, 0x81, 0x81, 0x80, 0x98, 0x2f, + 0x3b, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x3b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x3a, 0xff, 0xff, 0xff, 0xff, 0x3a, + 0xff, 0xff, 0xff, 0xfe, 0x3a, 0xff, 0xff, 0xff, + 0xfd, 0x3a, 0x7f, 0xff, 0xff, 0xff, 0x3a, 0x7f, + 0xff, 0xff, 0xfe, 0x3a, 0x00, 0x01, 0x00, 0x01, + 0x3a, 0x00, 0x01, 0x00, 0x00, 0x39, 0xff, 0xff, + 0x39, 0xff, 0xfe, 0x39, 0xff, 0xfd, 0x39, 0x01, + 0x00, 0x38, 0xff, 0x38, 0xfe, 0x38, 0xfd, 0x38, + 0x18, 0x37, 0x36, 0x20, 0x00, 0x00, 0x01, 0x16, + 0x17, 0x18, 0x18, 0x18, 0x19, 0x18, 0x1a, 0x18, + 0xfe, 0x18, 0xff, 0x19, 0x01, 0x00, 0x19, 0x01, + 0x01, 0x19, 0xff, 0xfe, 0x19, 0xff, 0xff, 0x1a, + 0x00, 0x01, 0x00, 0x00, 0x1a, 0x00, 0x01, 0x00, + 0x01, 0x1a, 0x00, 0x01, 0x00, 0x02, 0x1a, 0x7f, + 0xff, 0xff, 0xff, 0x1a, 0x7f, 0xff, 0xff, 0xff, + 0x1a, 0x80, 0x00, 0x00, 0x00, 0x1a, 0x80, 0x00, + 0x00, 0x01, 0x1a, 0xff, 0xff, 0xff, 0xfe, 0x1a, + 0xff, 0xff, 0xff, 0xff, 0x1b, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x1b, 0x7f, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1b, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + + +int EncodeRawTest() +{ + QCBOREncodeContext ECtx; + + QCBOREncode_Init(&ECtx, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf)); + QCBOREncode_OpenArray(&ECtx); + QCBOREncode_AddEncoded(&ECtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spFiveArrarys)); + QCBOREncode_AddEncoded(&ECtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedEncodedInts)); + QCBOREncode_CloseArray(&ECtx); + + UsefulBufC EncodedRawTest; + + if(QCBOREncode_Finish(&ECtx, &EncodedRawTest)) { + return -4; + } + + if(CheckResults(EncodedRawTest, spEncodeRawExpected)) { + return -5; + } + + return 0; +} + +/* + This returns a pointer to spBigBuf + */ +static int CreateMap(uint8_t **pEncoded, size_t *pEncodedLen) +{ + QCBOREncodeContext ECtx; + int nReturn = -1; + + *pEncoded = NULL; + *pEncodedLen = INT32_MAX; + size_t uFirstSizeEstimate = 0; + + // loop runs CBOR encoding twice. First with no buffer to + // calucate the length so buffer can be allocated correctly, + // and last with the buffer to do the actual encoding + do { + QCBOREncode_Init(&ECtx, (UsefulBuf){*pEncoded, *pEncodedLen}); + QCBOREncode_OpenMap(&ECtx); + QCBOREncode_AddInt64ToMap(&ECtx, "first integer", 42); + QCBOREncode_OpenArrayInMap(&ECtx, "an array of two strings"); + QCBOREncode_AddText(&ECtx, ((UsefulBufC) {"string1", 7})); + QCBOREncode_AddText(&ECtx, ((UsefulBufC) {"string2", 7})); + QCBOREncode_CloseArray(&ECtx); + QCBOREncode_OpenMapInMap(&ECtx, "map in a map"); + QCBOREncode_AddBytesToMap(&ECtx,"bytes 1", ((UsefulBufC) { "xxxx", 4})); + QCBOREncode_AddBytesToMap(&ECtx, "bytes 2",((UsefulBufC) { "yyyy", 4})); + QCBOREncode_AddInt64ToMap(&ECtx, "another int", 98); + QCBOREncode_AddTextToMap(&ECtx, "text 2", ((UsefulBufC) {"lies, damn lies and statistics", 30})); + QCBOREncode_CloseMap(&ECtx); + QCBOREncode_CloseMap(&ECtx); + + if(QCBOREncode_FinishGetSize(&ECtx, pEncodedLen)) + goto Done; + if(*pEncoded != NULL) { + if(uFirstSizeEstimate != *pEncodedLen) { + nReturn = 1; + } else { + nReturn = 0; + } + goto Done; + } + *pEncoded = spBigBuf; + uFirstSizeEstimate = *pEncodedLen; + + } while(1); + + Done: + return(nReturn); +} + +/* + A3 # map(3) + 6D # text(13) + 666972737420696E7465676572 # "first integer" + 18 2A # unsigned(42) + 77 # text(23) + 616E206172726179206F662074776F20737472696E6773 # "an array of two strings" + 82 # array(2) + 67 # text(7) + 737472696E6731 # "string1" + 67 # text(7) + 737472696E6732 # "string2" + 6C # text(12) + 6D617020696E2061206D6170 # "map in a map" + A4 # map(4) + 67 # text(7) + 62797465732031 # "bytes 1" + 44 # bytes(4) + 78787878 # "xxxx" + 67 # text(7) + 62797465732032 # "bytes 2" + 44 # bytes(4) + 79797979 # "yyyy" + 6B # text(11) + 616E6F7468657220696E74 # "another int" + 18 62 # unsigned(98) + 66 # text(6) + 746578742032 # "text 2" + 78 1E # text(30) + 6C6965732C2064616D6E206C69657320616E642073746174697374696373 # "lies, damn lies and statistics" + */ +static const uint8_t spValidMapEncoded[] = { + 0xa3, 0x6d, 0x66, 0x69, 0x72, 0x73, 0x74, 0x20, 0x69, 0x6e, + 0x74, 0x65, 0x67, 0x65, 0x72, 0x18, 0x2a, 0x77, 0x61, 0x6e, + 0x20, 0x61, 0x72, 0x72, 0x61, 0x79, 0x20, 0x6f, 0x66, 0x20, + 0x74, 0x77, 0x6f, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, + 0x73, 0x82, 0x67, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x31, + 0x67, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x32, 0x6c, 0x6d, + 0x61, 0x70, 0x20, 0x69, 0x6e, 0x20, 0x61, 0x20, 0x6d, 0x61, + 0x70, 0xa4, 0x67, 0x62, 0x79, 0x74, 0x65, 0x73, 0x20, 0x31, + 0x44, 0x78, 0x78, 0x78, 0x78, 0x67, 0x62, 0x79, 0x74, 0x65, + 0x73, 0x20, 0x32, 0x44, 0x79, 0x79, 0x79, 0x79, 0x6b, 0x61, + 0x6e, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x20, 0x69, 0x6e, 0x74, + 0x18, 0x62, 0x66, 0x74, 0x65, 0x78, 0x74, 0x20, 0x32, 0x78, + 0x1e, 0x6c, 0x69, 0x65, 0x73, 0x2c, 0x20, 0x64, 0x61, 0x6d, + 0x6e, 0x20, 0x6c, 0x69, 0x65, 0x73, 0x20, 0x61, 0x6e, 0x64, + 0x20, 0x73, 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, + 0x73 } ; + + +int MapEncodeTest() +{ + uint8_t *pEncodedMaps; + size_t nEncodedMapLen; + + if(CreateMap(&pEncodedMaps, &nEncodedMapLen)) { + return -1; + } + + int nReturn = 0; + if(memcmp(spValidMapEncoded, pEncodedMaps, sizeof(spValidMapEncoded))) + nReturn = 2; + + return(nReturn); +} + + +/* + @brief Encode the RTIC results + + @param[in] nRResult CBOR_SIMPLEV_TRUE, CBOR_SIMPLEV_FALSE or CBOR_SIMPLEV_NULL + @param[in] time Time stamp in UNIX epoch time or 0 for no time stamp + @param[in] szAlexString Diagnostic code. + @param[in[ pOut Buffer to put the result in + @param[in/out] pnLen Size of pOut buffer when called; length of data output in buffer on return + + @return + One of the CBOR encoder errors. QCBOR_SUCCESS, which is has value 0, if no error. + + The size of pOut should be 30 bytes plus the length of pnLen. If you make it too + short an error will be returned. This function will never write off the end + of the buffer passed to it. + + If the result is 0, then the correct encoded CBOR is in pOut and *pnLen is the + length of the encoded CBOR. + + */ + +static UsefulBufC FormatRTICResults(int nRResult, uint64_t time, const char *szType, const char *szAlexString, UsefulBuf Storage) +{ + // Buffer that the result will be written in to + // It is fixed size and small that a stack variable will be fine + // QCBOREncode will never write off the end of this buffer. If it won't fit QCBOREncode_Finish will return an error. + + // Context for the encoder + QCBOREncodeContext ECtx; + QCBOREncode_Init(&ECtx, Storage); + + // All the RTIC results are grouped in a CBOR Map which will get turned into a JSON Object + // Contents are label / value pairs + QCBOREncode_OpenMap(&ECtx); + + { // Brace / indention just to show CBOR encoding nesting + + // The result: 0 if scan happened and found nothing; 1 if it happened and found something wrong; 2 if it didn't happen + QCBOREncode_AddSimpleToMap(&ECtx, "integrity", nRResult); + + // Add the diagnostic code + QCBOREncode_AddSZStringToMap(&ECtx, "type", szType); + + // Add a time stamp + if(time) { + QCBOREncode_AddDateEpochToMap(&ECtx, "time", time); + } + + // Add the diagnostic code + QCBOREncode_AddSZStringToMap(&ECtx, "diag", szAlexString); + + // Open a subordinate map for telemtry data + QCBOREncode_OpenMapInMap(&ECtx, "telemetry"); + + { // Brace / indention just to show CBOR encoding nesting + + // Add a few fake integers and buffers for now. + QCBOREncode_AddInt64ToMap(&ECtx, "Shoe Size", 12); + + // Add a few fake integers and buffers for now. + QCBOREncode_AddInt64ToMap(&ECtx, "IQ", 0xffffffff); + + // Add a few fake integers and buffers for now. + static const uint8_t pPV[] = {0x66, 0x67, 0x00, 0x56, 0xaa, 0xbb, 0x01, 0x01}; + const UsefulBufC WSPV = {pPV, sizeof(pPV)}; + + QCBOREncode_AddBytesToMap(&ECtx, "WhaleSharkPatternVector", WSPV); + } + } + + // Close the telemetry map + QCBOREncode_CloseMap(&ECtx); + + // Close the map + QCBOREncode_CloseMap(&ECtx); + + UsefulBufC Result; + + QCBOREncode_Finish(&ECtx, &Result); + + return Result; +} + + +/* + A5 # map(5) + 69 # text(9) + 696E74656772697479 # "integrity" + F4 # primitive(20) + 64 # text(4) + 74797065 # "type" + 66 # text(6) + 726563656E74 # "recent" + 64 # text(4) + 74696D65 # "time" + C1 # tag(1) + 1A 580D4172 # unsigned(1477263730) + 64 # text(4) + 64696167 # "diag" + 6A # text(10) + 30784131654335303031 # "0xA1eC5001" + 69 # text(9) + 74656C656D65747279 # "telemetry" + A3 # map(3) + 69 # text(9) + 53686F652053697A65 # "Shoe Size" + 0C # unsigned(12) + 62 # text(2) + 4951 # "IQ" + 1A FFFFFFFF # unsigned(4294967295) + 77 # text(23) + 5768616C65536861726B5061747465726E566563746F72 # "WhaleSharkPatternVector" + 48 # bytes(8) + 66670056AABB0101 # "fg\x00V\xAA\xBB\x01\x01" + */ +static const uint8_t spExpectedRTIC[] = { + 0xa5, 0x69, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x69, 0x74, + 0x79, 0xf4, 0x64, 0x74, 0x79, 0x70, 0x65, 0x66, 0x72, 0x65, + 0x63, 0x65, 0x6e, 0x74, 0x64, 0x74, 0x69, 0x6d, 0x65, 0xc1, + 0x1a, 0x58, 0x0d, 0x41, 0x72, 0x64, 0x64, 0x69, 0x61, 0x67, + 0x6a, 0x30, 0x78, 0x41, 0x31, 0x65, 0x43, 0x35, 0x30, 0x30, + 0x31, 0x69, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, + 0x79, 0xa3, 0x69, 0x53, 0x68, 0x6f, 0x65, 0x20, 0x53, 0x69, + 0x7a, 0x65, 0x0c, 0x62, 0x49, 0x51, 0x1a, 0xff, 0xff, 0xff, + 0xff, 0x77, 0x57, 0x68, 0x61, 0x6c, 0x65, 0x53, 0x68, 0x61, + 0x72, 0x6b, 0x50, 0x61, 0x74, 0x74, 0x65, 0x72, 0x6e, 0x56, + 0x65, 0x63, 0x74, 0x6f, 0x72, 0x48, 0x66, 0x67, 0x00, 0x56, + 0xaa, 0xbb, 0x01, 0x01}; + + +int RTICResultsTest() +{ + const UsefulBufC Encoded = FormatRTICResults(CBOR_SIMPLEV_FALSE, 1477263730, + "recent", "0xA1eC5001", + UsefulBuf_FROM_BYTE_ARRAY(spBigBuf)); + if(UsefulBuf_IsNULLC(Encoded)) { + return -1; + } + + if(CheckResults(Encoded, spExpectedRTIC)) { + return -2; + } + + return 0; +} + + +/* + 82 # array(2) + 19 01C3 # unsigned(451) + 43 # bytes(3) + 1901D2 # "\x19\x01\xD2" +*/ +static const uint8_t spExpectedBstrWrap[] = {0x82, 0x19, 0x01, 0xC3, 0x43, 0x19, 0x01, 0xD2}; + +/* + Very basic bstr wrapping test + */ +int BstrWrapTest() +{ + QCBOREncodeContext EC; + + QCBOREncode_Init(&EC, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf)); + + QCBOREncode_OpenArray(&EC); + QCBOREncode_AddUInt64(&EC, 451); + + QCBOREncode_BstrWrap(&EC); + QCBOREncode_AddUInt64(&EC, 466); + + UsefulBufC Wrapped; + QCBOREncode_CloseBstrWrap(&EC, &Wrapped); + + QCBOREncode_CloseArray(&EC); + + UsefulBufC Encoded; + if(QCBOREncode_Finish(&EC, &Encoded)) { + return -1; + } + + if(CheckResults(Encoded, spExpectedBstrWrap)) { + return -2; + } + + /* Another test; see about handling length calculation */ + QCBOREncode_Init(&EC, (UsefulBuf){NULL, INT32_MAX}); + QCBOREncode_OpenArray(&EC); + QCBOREncode_BstrWrap(&EC); + QCBOREncode_OpenArray(&EC); + QCBOREncode_AddNULL(&EC); + QCBOREncode_CloseArray(&EC); + UsefulBufC BStr; + QCBOREncode_CloseBstrWrap(&EC, &BStr); + // 2 is one byte for an array of length 1 and 1 byte for a NULL + if(BStr.ptr != NULL || BStr.len != 2) { + return -5; + } + + return 0; +} + + + +int BstrWrapErrorTest() +{ + // -------------- Test closing a bstrwrap when it is an array that is open ----------- + QCBOREncodeContext EC; + + QCBOREncode_Init(&EC, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf)); + + QCBOREncode_OpenArray(&EC); + QCBOREncode_AddUInt64(&EC, 451); + + QCBOREncode_BstrWrap(&EC); + QCBOREncode_AddUInt64(&EC, 466); + QCBOREncode_OpenArray(&EC); + + UsefulBufC Wrapped; + QCBOREncode_CloseBstrWrap(&EC, &Wrapped); + + QCBOREncode_CloseArray(&EC); + + UsefulBufC Encoded2; + if(QCBOREncode_Finish(&EC, &Encoded2) != QCBOR_ERR_CLOSE_MISMATCH) { + return -1; + } + + // ----------- test closing a bstrwrap when nothing is open --------------------- + QCBOREncode_Init(&EC, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf)); + QCBOREncode_CloseBstrWrap(&EC, &Wrapped); + if(QCBOREncode_Finish(&EC, &Encoded2) != QCBOR_ERR_TOO_MANY_CLOSES) { + return -2; + } + + // --------------- test nesting too deep ---------------------------------- + QCBOREncode_Init(&EC, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf)); + for(int i = 1; i < 18; i++) { + QCBOREncode_BstrWrap(&EC); + } + QCBOREncode_AddBool(&EC, true); + + for(int i = 1; i < 18; i++) { + QCBOREncode_CloseBstrWrap(&EC, &Wrapped); + } + + if(QCBOREncode_Finish(&EC, &Encoded2) != QCBOR_ERR_ARRAY_NESTING_TOO_DEEP) { + return -3; + } + + return 0; +} + + + +// Part of bstr_wrap_nest_test +/* + 83 array with three + 53 byte string with 19 bytes + 01 #1 + 50 byte string with 16 bytes + 02 + 4D byte string with 13 bytes + 03 + 4A byte string with 10 bytes + 04 + 47 byte string with 7 bytes + 05 + 44 byte string with 4 bytes + 06 + 41 byte string with 1 byte + 07 + 01 + 02 + 03 + 04 + 05 + 06 + 07 + A2 map with two items + 18 20 label for byte string + 54 byte string of length 20 + 82 Array with two items + 10 The integer value 10 + A2 map with two items + 18 21 label for byte string + 44 byte string with 4 bytes + 81 array with 1 item + 11 integer value 11 + 18 30 integer value 30 + 18 40 integer label 40 + 65 68 65 6C 6C 6F text string hello + 18 31 integer value 31 + 18 41 integer label 41 + 65 68 65 6C 6C 6F text string hello + + + */ + + +/* + 83 # array(3) + 56 # bytes(22) + 00530150024D034A0447054406410700010203040506 # "\x00S\x01P\x02M\x03J\x04G\x05D\x06A\a\x00\x01\x02\x03\x04\x05\x06" + 07 # unsigned(7) + A2 # map(2) + 18 20 # unsigned(32) + 54 # bytes(20) + 8210A21821448111183018406568656C6C6F1831 # "\x82\x10\xA2\x18!D\x81\x11\x180\x18@ehello\x181" + 18 41 # unsigned(65) + 65 # text(5) + 68656C6C6F # "hello" + */ +static const uint8_t spExpectedDeepBstr[] = +{ + 0x83, 0x56, 0x00, 0x53, 0x01, 0x50, 0x02, 0x4D, + 0x03, 0x4A, 0x04, 0x47, 0x05, 0x44, 0x06, 0x41, + 0x07, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, + 0x07, 0xA2, 0x18, 0x20, 0x54, 0x82, 0x10, 0xA2, + 0x18, 0x21, 0x44, 0x81, 0x11, 0x18, 0x30, 0x18, + 0x40, 0x65, 0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x18, + 0x31, 0x18, 0x41, 0x65, 0x68, 0x65, 0x6C, 0x6C, + 0x6F +}; + +// Part of bstr_wrap_nest_test +static int DecodeNextNested(UsefulBufC Wrapped) +{ + int nReturn; + QCBORDecodeContext DC; + QCBORDecode_Init(&DC, Wrapped, QCBOR_DECODE_MODE_NORMAL); + + QCBORItem Item; + nReturn = QCBORDecode_GetNext(&DC, &Item); + if(nReturn) { + return -11; + } + if(Item.uDataType != QCBOR_TYPE_INT64) { + return -12; + } + + nReturn = QCBORDecode_GetNext(&DC, &Item); + if(nReturn == QCBOR_ERR_HIT_END) { + return 0; + } + if(Item.uDataType != QCBOR_TYPE_BYTE_STRING) { + return -13; + } + nReturn = DecodeNextNested(Item.val.string); + if(nReturn) { + return nReturn; + } + + nReturn = QCBORDecode_GetNext(&DC, &Item); + if(nReturn) { + return -14; + } + if(Item.uDataType != QCBOR_TYPE_INT64) { + return -15; + } + + if(QCBORDecode_Finish(&DC)) { + return -16; + } + + return 0; +} + +// Part of bstr_wrap_nest_test +static int DecodeNextNested2(UsefulBufC Wrapped) +{ + int nReturn; + QCBORDecodeContext DC; + QCBORDecode_Init(&DC, Wrapped, QCBOR_DECODE_MODE_NORMAL); + + QCBORItem Item; + nReturn = QCBORDecode_GetNext(&DC, &Item); + if(nReturn) { + return -11; + } + if(Item.uDataType != QCBOR_TYPE_ARRAY) { + return -12; + } + + nReturn = QCBORDecode_GetNext(&DC, &Item); + if(nReturn) { + return -11; + } + if(Item.uDataType != QCBOR_TYPE_INT64) { + return -12; + } + + nReturn = QCBORDecode_GetNext(&DC, &Item); + if(nReturn) { + return -11; + } + if(Item.uDataType != QCBOR_TYPE_MAP) { + return 0; + } + + nReturn = QCBORDecode_GetNext(&DC, &Item); + if(nReturn) { + return -11; + } + if(Item.uDataType != QCBOR_TYPE_BYTE_STRING) { + return -13; + } + nReturn = DecodeNextNested2(Item.val.string); + if(nReturn) { + return nReturn; + } + + nReturn = QCBORDecode_GetNext(&DC, &Item); + if(nReturn) { + return -11; + } + if(Item.uDataType != QCBOR_TYPE_TEXT_STRING) { + return -12; + } + nReturn = QCBORDecode_GetNext(&DC, &Item); + if(nReturn) { + return -11; + } + if(Item.uDataType != QCBOR_TYPE_INT64) { + return -12; + } + + if(QCBORDecode_Finish(&DC)) { + return -16; + } + + return 0; +} + + +int BstrWrapNestTest() +{ + QCBOREncodeContext EC; + QCBOREncode_Init(&EC, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf)); + + // ---- Make a complicated nested CBOR structure --- +#define BSTR_TEST_DEPTH 10 + + QCBOREncode_OpenArray(&EC); + + for(int i = 0; i < BSTR_TEST_DEPTH-2; i++) { + QCBOREncode_BstrWrap(&EC); + QCBOREncode_AddUInt64(&EC, i); + } + + for(int i = 0; i < BSTR_TEST_DEPTH-2; i++) { + QCBOREncode_CloseBstrWrap(&EC, NULL); + QCBOREncode_AddUInt64(&EC, i); + } + + for(int i = 0; i < (BSTR_TEST_DEPTH-2)/3; i++) { + QCBOREncode_OpenMap(&EC); + QCBOREncode_BstrWrapInMapN(&EC, i+0x20); + QCBOREncode_OpenArray(&EC); + QCBOREncode_AddUInt64(&EC, i+0x10); + } + + for(int i = 0; i < (BSTR_TEST_DEPTH-2)/3; i++) { + QCBOREncode_CloseArray(&EC); + QCBOREncode_AddUInt64(&EC, i+0x30); + QCBOREncode_CloseBstrWrap(&EC, NULL); + QCBOREncode_AddSZStringToMapN(&EC, i+0x40, "hello"); + QCBOREncode_CloseMap(&EC); + } + QCBOREncode_CloseArray(&EC); + + UsefulBufC Encoded; + if(QCBOREncode_Finish(&EC, &Encoded)) { + return -1; + } + + // ---Compare it to expected. Expected was hand checked with use of CBOR playground ---- + if(UsefulBuf_Compare(UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedDeepBstr), Encoded)) { + return -25; + } + + + // ---- Decode it and see if it is OK ------ + QCBORDecodeContext DC; + QCBORDecode_Init(&DC, Encoded, QCBOR_DECODE_MODE_NORMAL); + + QCBORItem Item; + QCBORDecode_GetNext(&DC, &Item); + if(Item.uDataType != QCBOR_TYPE_ARRAY || Item.val.uCount != 3) { + return -2; + } + + QCBORDecode_GetNext(&DC, &Item); + if(Item.uDataType != QCBOR_TYPE_BYTE_STRING) { + return -3; + } + + int nReturn = DecodeNextNested(Item.val.string); + if(nReturn) { + return nReturn; + } + + nReturn = QCBORDecode_GetNext(&DC, &Item); + if(nReturn) { + return -11; + } + if(Item.uDataType != QCBOR_TYPE_INT64) { + return -12; + } + + QCBORDecode_GetNext(&DC, &Item); + if(Item.uDataType != QCBOR_TYPE_MAP || Item.val.uCount != 2) { + return -2; + } + + QCBORDecode_GetNext(&DC, &Item); + if(Item.uDataType != QCBOR_TYPE_BYTE_STRING) { + return -3; + } + nReturn = DecodeNextNested2(Item.val.string); + if(nReturn) { + return nReturn; + } + + nReturn = QCBORDecode_GetNext(&DC, &Item); + if(nReturn) { + return -11; + } + if(Item.uDataType != QCBOR_TYPE_TEXT_STRING) { + return -12; + } + + if(QCBORDecode_Finish(&DC)) { + return -16; + } + + return 0; +} + + +static const uint8_t spSignature[] = { + 0x8e, 0xb3, 0x3e, 0x4c, 0xa3, 0x1d, 0x1c, 0x46, 0x5a, 0xb0, + 0x5a, 0xac, 0x34, 0xcc, 0x6b, 0x23, 0xd5, 0x8f, 0xef, 0x5c, + 0x08, 0x31, 0x06, 0xc4, 0xd2, 0x5a, 0x91, 0xae, 0xf0, 0xb0, + 0x11, 0x7e, 0x2a, 0xf9, 0xa2, 0x91, 0xaa, 0x32, 0xe1, 0x4a, + 0xb8, 0x34, 0xdc, 0x56, 0xed, 0x2a, 0x22, 0x34, 0x44, 0x54, + 0x7e, 0x01, 0xf1, 0x1d, 0x3b, 0x09, 0x16, 0xe5, 0xa4, 0xc3, + 0x45, 0xca, 0xcb, 0x36}; + +/* + D2 # tag(18) + 84 # array(4) + 43 # bytes(3) + A10126 # "\xA1\x01&" + A1 # map(1) + 04 # unsigned(4) + 42 # bytes(2) + 3131 # "11" + 54 # bytes(20) + 546869732069732074686520636F6E74656E742E # "This is the content." + 58 40 # bytes(64) + 8EB33E4CA31D1C465AB05AAC34CC6B23D58FEF5C083106C4D25A91AEF0B0117E2AF9A291AA32E14AB834DC56ED2A223444547E01F11D3B0916E5A4C345CACB36 # "\x8E\xB3>L\xA3\x1D\x1CFZ\xB0Z\xAC4\xCCk#\xD5\x8F\xEF\\\b1\x06\xC4\xD2Z\x91\xAE\xF0\xB0\x11~*\xF9\xA2\x91\xAA2\xE1J\xB84\xDCV\xED*\"4DT~\x01\xF1\x1D;\t\x16\xE5\xA4\xC3E\xCA\xCB6" + */ +static const uint8_t spExpected[] = { + 0xD2, 0x84, 0x43, 0xA1, 0x01, 0x26, 0xA1, 0x04, 0x42, 0x31, + 0x31, 0x54, 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x63, 0x6F, 0x6E, 0x74, 0x65, 0x6E, + 0x74, 0x2E, 0x58, 0x40, 0x8E, 0xB3, 0x3E, 0x4C, 0xA3, 0x1D, + 0x1C, 0x46, 0x5A, 0xB0, 0x5A, 0xAC, 0x34, 0xCC, 0x6B, 0x23, + 0xD5, 0x8F, 0xEF, 0x5C, 0x08, 0x31, 0x06, 0xC4, 0xD2, 0x5A, + 0x91, 0xAE, 0xF0, 0xB0, 0x11, 0x7E, 0x2A, 0xF9, 0xA2, 0x91, + 0xAA, 0x32, 0xE1, 0x4A, 0xB8, 0x34, 0xDC, 0x56, 0xED, 0x2A, + 0x22, 0x34, 0x44, 0x54, 0x7E, 0x01, 0xF1, 0x1D, 0x3B, 0x09, + 0x16, 0xE5, 0xA4, 0xC3, 0x45, 0xCA, 0xCB, 0x36}; + +/* + this corresponds exactly to the example in RFC 8152 + section C.2.1. This doesn't actually verify the signature + though that would be nice as it would make the test + really good. That would require bring in ECDSA crypto + to this test. + */ +int CoseSign1TBSTest() +{ + // All of this is from RFC 8152 C.2.1 + const char *szKid = "11"; + const UsefulBufC Kid = UsefulBuf_FromSZ(szKid); + const char *szPayload = "This is the content."; + const UsefulBufC Payload = UsefulBuf_FromSZ(szPayload); + static const uint8_t pProtectedHeaders[] = {0xa1, 0x01, 0x26}; + const UsefulBufC ProtectedHeaders = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pProtectedHeaders); + + // It would be good to compare this to the output from + // a COSE implementation like COSE-C. It has been checked + // against the CBOR playground. + const UsefulBufC Signature = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spSignature); + + QCBOREncodeContext EC; + QCBOREncode_Init(&EC, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf)); + + // top level array for cose sign1, 18 is the tag for COSE sign + QCBOREncode_AddTag(&EC, CBOR_TAG_COSE_SIGN1); + QCBOREncode_OpenArray(&EC); + + // Add protected headers + QCBOREncode_AddBytes(&EC, ProtectedHeaders); + + // Empty map with unprotected headers + QCBOREncode_OpenMap(&EC); + QCBOREncode_AddBytesToMapN(&EC, 4, Kid); + QCBOREncode_CloseMap(&EC); + + // The payload + UsefulBufC WrappedPayload; + QCBOREncode_BstrWrap(&EC); + QCBOREncode_AddEncoded(&EC, Payload); // Payload is not actually CBOR in example C.2.1 + QCBOREncode_CloseBstrWrap(&EC, &WrappedPayload); + + // Check we got back the actual payload expected + if(UsefulBuf_Compare(WrappedPayload, Payload)) { + return -1; + } + + // The signature + QCBOREncode_AddBytes(&EC, Signature); + QCBOREncode_CloseArray(&EC); + + // Finish and check the results + UsefulBufC COSE_Sign1; + if(QCBOREncode_Finish(&EC, &COSE_Sign1)) { + return -2; + } + + // 98 is the size from RFC 8152 C.2.1 + if(COSE_Sign1.len != 98) { + return -3; + } + + if(CheckResults(COSE_Sign1, spExpected)) { + return -4; + } + + return 0; +} + + +int EncodeErrorTests() +{ + QCBOREncodeContext EC; + + + // ------ Test for QCBOR_ERR_BUFFER_TOO_LARGE ------ + // Do all of these tests with NULL buffers so no actual large allocations are neccesary + UsefulBuf Buffer = (UsefulBuf){NULL, UINT32_MAX}; + + // First verify no error from a big buffer + QCBOREncode_Init(&EC, Buffer); + QCBOREncode_OpenArray(&EC); + // 6 is the CBOR overhead for opening the array and encodng the length + // This exactly fills the buffer. + QCBOREncode_AddBytes(&EC, (UsefulBufC){NULL, UINT32_MAX-6}); + QCBOREncode_CloseArray(&EC); + size_t xx; + if(QCBOREncode_FinishGetSize(&EC, &xx) != QCBOR_SUCCESS) { + return -1; + } + + // Second verify error from an array in encoded output too large + QCBOREncode_Init(&EC, Buffer); + QCBOREncode_OpenArray(&EC); + QCBOREncode_AddBytes(&EC, (UsefulBufC){NULL, UINT32_MAX-6}); + QCBOREncode_OpenArray(&EC); // Where QCBOR internally encounters and records error + QCBOREncode_CloseArray(&EC); + QCBOREncode_CloseArray(&EC); + if(QCBOREncode_FinishGetSize(&EC, &xx) != QCBOR_ERR_BUFFER_TOO_LARGE) { + return -2; + } + + // Third, fit an array in exactly at max position allowed + QCBOREncode_Init(&EC, Buffer); + QCBOREncode_OpenArray(&EC); + QCBOREncode_AddBytes(&EC, (UsefulBufC){NULL, QCBOR_MAX_ARRAY_OFFSET-6}); + QCBOREncode_OpenArray(&EC); + QCBOREncode_CloseArray(&EC); + QCBOREncode_CloseArray(&EC); + if(QCBOREncode_FinishGetSize(&EC, &xx) != QCBOR_SUCCESS) { + return -10; + } + + + // ----- QCBOR_ERR_BUFFER_TOO_SMALL -------------- + // Work close to the 4GB size limit for a better test + const uint32_t uLargeSize = UINT32_MAX - 1024; + UsefulBuf Large = (UsefulBuf){NULL,uLargeSize}; + + QCBOREncode_Init(&EC, Large); + QCBOREncode_OpenArray(&EC); + QCBOREncode_AddBytes(&EC, (UsefulBufC){NULL, uLargeSize/2 + 1}); + QCBOREncode_CloseArray(&EC); + if(QCBOREncode_FinishGetSize(&EC, &xx) != QCBOR_SUCCESS) { + // Making sure it succeeds when it should first + return -3; + } + + QCBOREncode_Init(&EC, Large); + QCBOREncode_OpenArray(&EC); + QCBOREncode_AddBytes(&EC, (UsefulBufC){NULL, uLargeSize/2 + 1}); + QCBOREncode_AddBytes(&EC, (UsefulBufC){NULL, uLargeSize/2}); + QCBOREncode_CloseArray(&EC); + if(QCBOREncode_FinishGetSize(&EC, &xx) != QCBOR_ERR_BUFFER_TOO_SMALL) { + // Now just 1 byte over, see that it fails + return -4; + } + + + // ----- QCBOR_ERR_ARRAY_NESTING_TOO_DEEP ------- + QCBOREncode_Init(&EC, Large); + for(int i = QCBOR_MAX_ARRAY_NESTING; i > 0; i--) { + QCBOREncode_OpenArray(&EC); + } + for(int i = QCBOR_MAX_ARRAY_NESTING; i > 0; i--) { + QCBOREncode_CloseArray(&EC); + } + if(QCBOREncode_FinishGetSize(&EC, &xx) != QCBOR_SUCCESS) { + // Making sure it succeeds when it should first + return -5; + } + + QCBOREncode_Init(&EC, Large); + for(int i = QCBOR_MAX_ARRAY_NESTING+1; i > 0; i--) { + QCBOREncode_OpenArray(&EC); + } + for(int i = QCBOR_MAX_ARRAY_NESTING+1; i > 0; i--) { + QCBOREncode_CloseArray(&EC); + } + if(QCBOREncode_FinishGetSize(&EC, &xx) != QCBOR_ERR_ARRAY_NESTING_TOO_DEEP) { + // One more level to cause error + return -6; + } + + + // ------ QCBOR_ERR_TOO_MANY_CLOSES -------- + QCBOREncode_Init(&EC, Large); + for(int i = QCBOR_MAX_ARRAY_NESTING; i > 0; i--) { + QCBOREncode_OpenArray(&EC); + } + for(int i = QCBOR_MAX_ARRAY_NESTING+1; i > 0; i--) { + QCBOREncode_CloseArray(&EC); + } + if(QCBOREncode_FinishGetSize(&EC, &xx) != QCBOR_ERR_TOO_MANY_CLOSES) { + // One more level to cause error + return -7; + } + + + // ------ QCBOR_ERR_CLOSE_MISMATCH -------- + QCBOREncode_Init(&EC, Large); + QCBOREncode_OpenArray(&EC); + UsefulBufC Wrap; + QCBOREncode_CloseBstrWrap(&EC, &Wrap); + if(QCBOREncode_FinishGetSize(&EC, &xx) != QCBOR_ERR_CLOSE_MISMATCH) { + return -8; + } + + + // ------ QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN --------- + QCBOREncode_Init(&EC, Large); + for(int i = QCBOR_MAX_ARRAY_NESTING; i > 0; i--) { + QCBOREncode_OpenArray(&EC); + } + for(int i = QCBOR_MAX_ARRAY_NESTING-1; i > 0; i--) { + QCBOREncode_CloseArray(&EC); + } + if(QCBOREncode_FinishGetSize(&EC, &xx) != QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN) { + // One more level to cause error + return -9; + } + + /* QCBOR_ERR_ARRAY_TOO_LONG is not tested here as + it would require a 64KB of RAM to test */ + + return 0; +} + diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/qcbor/test/qcbor_encode_tests.h b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/qcbor/test/qcbor_encode_tests.h new file mode 100644 index 0000000..49362c6 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/qcbor/test/qcbor_encode_tests.h @@ -0,0 +1,146 @@ +/*============================================================================== + Copyright (c) 2016-2018, The Linux Foundation. + Copyright (c) 2018-2019, Laurence Lundblade. + All rights reserved. + SPDX-License-Identifier: BSD-3-Clause + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of The Linux Foundation nor the names of its + contributors, nor the name "Laurence Lundblade" may be used to + endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ==============================================================================*/ + +#ifndef __QCBOR__qcbor_encode_tests__ +#define __QCBOR__qcbor_encode_tests__ + +#include "qcbor.h" + + +/* + Notes: + + - All the functions in qcbor.h are called once in the aggregation of all the tests below. + + - All the types that are supported are given as input and parsed by these tests + + - There is some hostile input such as invalid lengths and CBOR too complex + and types this parser doesn't handle + + */ + + +/* + Most basic test. + */ +int BasicEncodeTest(void); + + +/* + Encode lots of integer values, particularly around the boundary and make sure they + Match the expected binary output. Primarily an encoding test. + */ +int IntegerValuesTest1(void); + + + +/* + Create nested arrays to the max depth allowed and make sure it succeeds. + This is an encoding test. + */ +int ArrayNestingTest1(void); + + +/* + Create nested arrays to one more than the meax depth and make sure it fails. + This is an encoding test. + */ +int ArrayNestingTest2(void); + + +/* + Encoding test. + Create arrays to max depth and close one extra time and look for correct error code + */ +int ArrayNestingTest3(void); + + +/* + This tests the QCBOREncode_AddRaw() function by adding two chunks or RAWCBOR to an + array and comparing with expected values. This is an encoding test. + */ +int EncodeRawTest(void); + + +/* + This creates a somewhat complicated CBOR MAP and verifies it against expected + data. This is an encoding test. + */ +int MapEncodeTest(void); + + + +/* + Encodes a goodly number of floats and doubles and checks encoding is right + */ +int FloatValuesTest1(void); + + +/* + Encodes true, false and the like + */ +int SimpleValuesTest1(void); + + +/* + Encodes most data formats that are supported */ +int EncodeDateTest(void); + + +/* + Encodes particular data structure that a particular app will need... + */ +int RTICResultsTest(void); + + +/* + Calls all public encode methods in qcbor.h once. + */ +int AllAddMethodsTest(void); + +/* + The binary string wrapping of maps and arrays used by COSE + */ +int BstrWrapTest(void); + +int BstrWrapErrorTest(void); + +int BstrWrapNestTest(void); + +int CoseSign1TBSTest(void); + +int EncodeErrorTests(void); + + + +#endif /* defined(__QCBOR__qcbor_encode_tests__) */ diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/qcbor/test/run_tests.c b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/qcbor/test/run_tests.c new file mode 100644 index 0000000..6e35620 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/qcbor/test/run_tests.c @@ -0,0 +1,285 @@ +/*============================================================================== + run_tests.c -- test aggregator and results reporting + + Copyright (c) 2018-2019, Laurence Lundblade. All rights reserved. + + SPDX-License-Identifier: BSD-3-Clause + + See BSD-3-Clause license in README.md + + Created on 9/30/18 + ==============================================================================*/ + +#include "run_tests.h" +#include "UsefulBuf.h" +#include + +#include "float_tests.h" +#include "qcbor_decode_tests.h" +#include "qcbor_encode_tests.h" +#include "UsefulBuf_Tests.h" + + + +// Used to test RunTests +int fail_test() +{ + return -44; +} + + + + +/* + Convert a number up to 999999999 to a string. This is so sprintf doesn't + have to be linked in so as to minimized dependencies even in test code. + */ +const char *NumToString(int32_t nNum, UsefulBuf StringMem) +{ + const int32_t nMax = 1000000000; + + UsefulOutBuf OutBuf; + UsefulOutBuf_Init(&OutBuf, StringMem); + + if(nNum < 0) { + UsefulOutBuf_AppendByte(&OutBuf, '-'); + nNum = -nNum; + } + if(nNum > nMax-1) { + return "XXX"; + } + + bool bDidSomeOutput = false; + for(int n = nMax; n > 0; n/=10) { + int x = nNum/n; + if(x || bDidSomeOutput){ + bDidSomeOutput = true; + UsefulOutBuf_AppendByte(&OutBuf, '0' + x); + nNum -= x * n; + } + } + if(!bDidSomeOutput){ + UsefulOutBuf_AppendByte(&OutBuf, '0'); + } + UsefulOutBuf_AppendByte(&OutBuf, '\0'); + + return UsefulOutBuf_GetError(&OutBuf) ? "" : StringMem.ptr; +} + + + + +typedef int (test_fun_t)(void); +typedef const char * (test_fun2_t)(void); + + +#define TEST_ENTRY(test_name) {#test_name, test_name, true} +#define TEST_ENTRY_DISABLED(test_name) {#test_name, test_name, false} + +typedef struct { + const char *szTestName; + test_fun_t *test_fun; + bool bEnabled; +} test_entry; + +typedef struct { + const char *szTestName; + test_fun2_t *test_fun; + bool bEnabled; +} test_entry2; + +test_entry2 s_tests2[] = { + TEST_ENTRY(UBUTest_CopyUtil), + TEST_ENTRY(UOBTest_NonAdversarial), + TEST_ENTRY(TestBasicSanity), + TEST_ENTRY(UOBTest_BoundaryConditionsTest), + TEST_ENTRY(UBMacroConversionsTest), + TEST_ENTRY(UBUtilTests), + TEST_ENTRY(UIBTest_IntegerFormat) +}; + + +test_entry s_tests[] = { + TEST_ENTRY(ParseMapAsArrayTest), + TEST_ENTRY_DISABLED(AllocAllStringsTest), + TEST_ENTRY(IndefiniteLengthNestTest), + TEST_ENTRY(NestedMapTestIndefLen), + TEST_ENTRY(ParseSimpleTest), + TEST_ENTRY(EncodeRawTest), + TEST_ENTRY(RTICResultsTest), + TEST_ENTRY(MapEncodeTest), + TEST_ENTRY(ArrayNestingTest1), + TEST_ENTRY(ArrayNestingTest2), + TEST_ENTRY(ArrayNestingTest3), + TEST_ENTRY(EncodeDateTest), + TEST_ENTRY(SimpleValuesTest1), + TEST_ENTRY(IntegerValuesTest1), + TEST_ENTRY(AllAddMethodsTest), + TEST_ENTRY(ParseTooDeepArrayTest), + TEST_ENTRY(ComprehensiveInputTest), + TEST_ENTRY(ParseMapTest), + TEST_ENTRY_DISABLED(IndefiniteLengthArrayMapTest), + TEST_ENTRY(BasicEncodeTest), + TEST_ENTRY(NestedMapTest), + TEST_ENTRY(BignumParseTest), + TEST_ENTRY(OptTagParseTest), + TEST_ENTRY(DateParseTest), + TEST_ENTRY(ShortBufferParseTest2), + TEST_ENTRY(ShortBufferParseTest), + TEST_ENTRY(ParseDeepArrayTest), + TEST_ENTRY(SimpleArrayTest), + TEST_ENTRY(IntegerValuesParseTest), + TEST_ENTRY_DISABLED(MemPoolTest), + TEST_ENTRY_DISABLED(IndefiniteLengthStringTest), + TEST_ENTRY(HalfPrecisionDecodeBasicTests), + TEST_ENTRY(DoubleAsSmallestTest), + TEST_ENTRY(HalfPrecisionAgainstRFCCodeTest), + TEST_ENTRY(BstrWrapTest), + TEST_ENTRY(BstrWrapErrorTest), + TEST_ENTRY(BstrWrapNestTest), + TEST_ENTRY(CoseSign1TBSTest), + TEST_ENTRY(StringDecoderModeFailTest), + TEST_ENTRY_DISABLED(BigComprehensiveInputTest), + TEST_ENTRY(EncodeErrorTests), + //TEST_ENTRY(fail_test), +}; + + +int RunTests(const char *szTestNames[], OutputStringCB pfOutput, void *poutCtx, int *pNumTestsRun) +{ + int nTestsFailed = 0; + int nTestsRun = 0; + UsefulBuf_MAKE_STACK_UB(StringStorage, 5); + + test_entry2 *t2; + const test_entry2 *s_tests2_end = s_tests2 + sizeof(s_tests2)/sizeof(test_entry2); + + for(t2 = s_tests2; t2 < s_tests2_end; t2++) { + if(szTestNames[0]) { + // Some tests have been named + const char **szRequestedNames; + for(szRequestedNames = szTestNames; *szRequestedNames; szRequestedNames++) { + if(!strcmp(t2->szTestName, *szRequestedNames)) { + break; // Name matched + } + } + if(*szRequestedNames == NULL) { + // Didn't match this test + continue; + } + } else { + // no tests named, but don't run "disabled" tests + if(!t2->bEnabled) { + // Don't run disabled tests when all tests are being run + // as indicated by no specific test names being given + continue; + } + } + + const char * szTestResult = (t2->test_fun)(); + nTestsRun++; + if(pfOutput) { + (*pfOutput)(t2->szTestName, poutCtx, 0); + } + + if(szTestResult) { + if(pfOutput) { + (*pfOutput)(" FAILED (returned ", poutCtx, 0); + (*pfOutput)(szTestResult, poutCtx, 0); + (*pfOutput)(")", poutCtx, 1); + } + nTestsFailed++; + } else { + if(pfOutput) { + (*pfOutput)( " PASSED", poutCtx, 1); + } + } + } + + + test_entry *t; + const test_entry *s_tests_end = s_tests + sizeof(s_tests)/sizeof(test_entry); + + for(t = s_tests; t < s_tests_end; t++) { + if(szTestNames[0]) { + // Some tests have been named + const char **szRequestedNames; + for(szRequestedNames = szTestNames; *szRequestedNames; szRequestedNames++) { + if(!strcmp(t->szTestName, *szRequestedNames)) { + break; // Name matched + } + } + if(*szRequestedNames == NULL) { + // Didn't match this test + continue; + } + } else { + // no tests named, but don't run "disabled" tests + if(!t->bEnabled) { + // Don't run disabled tests when all tests are being run + // as indicated by no specific test names being given + continue; + } + } + + int nTestResult = (t->test_fun)(); + nTestsRun++; + if(pfOutput) { + (*pfOutput)(t->szTestName, poutCtx, 0); + } + + if(nTestResult) { + if(pfOutput) { + (*pfOutput)(" FAILED (returned ", poutCtx, 0); + (*pfOutput)(NumToString(nTestResult, StringStorage), poutCtx, 0); + (*pfOutput)(")", poutCtx, 1); + } + nTestsFailed++; + } else { + if(pfOutput) { + (*pfOutput)( " PASSED", poutCtx, 1); + } + } + } + + if(pNumTestsRun) { + *pNumTestsRun = nTestsRun; + } + + if(pfOutput) { + (*pfOutput)( "SUMMARY: ", poutCtx, 0); + (*pfOutput)( NumToString(nTestsRun, StringStorage), poutCtx, 0); + (*pfOutput)( " tests run; ", poutCtx, 0); + (*pfOutput)( NumToString(nTestsFailed, StringStorage), poutCtx, 0); + (*pfOutput)( " tests failed", poutCtx, 1); + } + + return nTestsFailed; +} + + + + +static void PrintSize(const char *szWhat, uint32_t uSize, OutputStringCB pfOutput, void *pOutCtx) +{ + UsefulBuf_MAKE_STACK_UB(buffer, 20); + + (*pfOutput)(szWhat, pOutCtx, 0); + (*pfOutput)(" ", pOutCtx, 0); + (*pfOutput)(NumToString(uSize, buffer), pOutCtx, 0); + (*pfOutput)("", pOutCtx, 1); +} + +void PrintSizes(OutputStringCB pfOutput, void *pOutCtx) +{ + // Type and size of return from sizeof() varies. These will never be large so cast is safe + PrintSize("sizeof(QCBORTrackNesting)", (uint32_t)sizeof(QCBORTrackNesting), pfOutput, pOutCtx); + PrintSize("sizeof(QCBOREncodeContext)", (uint32_t)sizeof(QCBOREncodeContext), pfOutput, pOutCtx); + PrintSize("sizeof(QCBORDecodeNesting)", (uint32_t)sizeof(QCBORDecodeNesting), pfOutput, pOutCtx); + PrintSize("sizeof(QCBORDecodeContext)", (uint32_t)sizeof(QCBORDecodeContext), pfOutput, pOutCtx); + PrintSize("sizeof(QCBORItem)", (uint32_t)sizeof(QCBORItem), pfOutput, pOutCtx); + PrintSize("sizeof(QCBORStringAllocator)",(uint32_t)sizeof(QCBORStringAllocator), pfOutput, pOutCtx); + PrintSize("sizeof(QCBORTagListIn)", (uint32_t)sizeof(QCBORTagListIn), pfOutput, pOutCtx); + PrintSize("sizeof(QCBORTagListOut)", (uint32_t)sizeof(QCBORTagListOut), pfOutput, pOutCtx); + (*pfOutput)("", pOutCtx, 1); +} diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/qcbor/test/run_tests.h b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/qcbor/test/run_tests.h new file mode 100644 index 0000000..734d4f8 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/qcbor/test/run_tests.h @@ -0,0 +1,66 @@ +/*============================================================================== + run_tests.h -- test aggregator and results reporting + + Copyright (c) 2018-2019, Laurence Lundblade. All rights reserved. + + SPDX-License-Identifier: BSD-3-Clause + + See BSD-3-Clause license in README.md + + Created 9/30/18 + ==============================================================================*/ + +/** + @file run_tests.h +*/ + +/** + @brief Type for function to output a text string + + @param[in] szString The string to output + @param[in] pOutCtx A context pointer; NULL if not needed + @param[in] bNewline If non-zero, output a newline after the string + + This is a prototype of a function to be passed to RunTests() to + output text strings. + + This can be implemented with stdio (if available) using a straight + call to fputs() where the FILE * is passed as the pOutCtx as shown in + the example code below. This code is for Linux where the newline is + a \\n. Windows usually prefers \\r\\n. + + @code + static void fputs_wrapper(const char *szString, void *pOutCtx, int bNewLine) + { + fputs(szString, (FILE *)pOutCtx); + if(bNewLine) { + fputs("\n", pOutCtx); + } + } + @endcode +*/ +typedef void (*OutputStringCB)(const char *szString, void *pOutCtx, int bNewline); + + +/** + @brief Runs the QCBOR tests. + + @param[in] szTestNames An argv-style list of test names to run. If + empty, all are run. + @param[in] pfOutput Function that is called to output text strings. + @param[in] pOutCtx Context pointer passed to output function. + @param[out] pNumTestsRun Returns the number of tests run. May be NULL. + + @return The number of tests that failed. Zero means overall success. + */ +int RunTests(const char *szTestNames[], OutputStringCB pfOutput, void *pOutCtx, int *pNumTestsRun); + + +/** + @brief Print sizes of encoder / decoder contexts. + + @param[in] pfOutput Function that is called to output text strings. + @param[in] pOutCtx Context pointer passed to output function. + */ +void PrintSizes(OutputStringCB pfOutput, void *pOutCtx); + diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/tfm_client.h b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/tfm_client.h new file mode 100755 index 0000000..ee2645d --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/attestation/tfm_client.h @@ -0,0 +1,32 @@ +/* +* Copyright (c) 2018-2019 ARM Limited. All rights reserved. +* +* SPDX-License-Identifier: Apache-2.0 +* +* Licensed under the Apache License, Version 2.0 (the License); you may +* not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an AS IS BASIS, WITHOUT +* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#ifndef __TFM_CLIENT_H__ +#define __TFM_CLIENT_H__ + +#include "psa/client.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* __TFM_CLIENT_H__ */ diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/crypto/COMPONENT_PSA_SRV_IPC/crypto_platform_spe.h b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/crypto/COMPONENT_PSA_SRV_IPC/crypto_platform_spe.h new file mode 100644 index 0000000..05fe728 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/crypto/COMPONENT_PSA_SRV_IPC/crypto_platform_spe.h @@ -0,0 +1,179 @@ +/** + * \file psa/crypto_platform_spe.h + * + * \brief PSA cryptography module: Mbed TLS platfom definitions + */ +/* + * Copyright (C) 2018, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#ifndef PSA_CRYPTO_SPE_PLATFORM_H +#define PSA_CRYPTO_SPE_PLATFORM_H + +/* Include the Mbed TLS configuration file, the way Mbed TLS does it + * in each of its header files. */ +#if !defined(MBEDTLS_CONFIG_FILE) +#include "../mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +/** \defgroup PSA Crypto APIs +* @{ +*/ + +/** \brief psa_s_function_t enum defines for all the available functions in PSA Crypto. */ +typedef enum psa_sec_function_s { + PSA_CRYPTO_INVALID, + PSA_GET_KEY_ATTRIBUTES, + PSA_OPEN_KEY, + PSA_CLOSE_KEY, + PSA_IMPORT_KEY, + PSA_DESTROY_KEY, + PSA_EXPORT_KEY, + PSA_EXPORT_PUBLIC_KEY, + PSA_COPY_KEY, + PSA_HASH_COMPUTE, + PSA_HASH_COMPARE, + PSA_HASH_SETUP, + PSA_HASH_UPDATE, + PSA_HASH_FINISH, + PSA_HASH_VERIFY, + PSA_HASH_ABORT, + PSA_HASH_CLONE, + PSA_HASH_CLONE_BEGIN, + PSA_HASH_CLONE_END, + PSA_MAC_COMPUTE, + PSA_MAC_VERIFY, + PSA_MAC_SIGN_SETUP, + PSA_MAC_VERIFY_SETUP, + PSA_MAC_UPDATE, + PSA_MAC_SIGN_FINISH, + PSA_MAC_VERIFY_FINISH, + PSA_MAC_ABORT, + PSA_CIPHER_ENCRYPT, + PSA_CIPHER_DECRYPT, + PSA_CIPHER_ENCRYPT_SETUP, + PSA_CIPHER_DECRYPT_SETUP, + PSA_CIPHER_GENERATE_IV, + PSA_CIPHER_SET_IV, + PSA_CIPHER_UPDATE, + PSA_CIPHER_FINISH, + PSA_CIPHER_ABORT, + PSA_AEAD_ENCRYPT, + PSA_AEAD_DECRYPT, + PSA_AEAD_ENCRYPT_SETUP, + PSA_AEAD_DECRYPT_SETUP, + PSA_AEAD_GENERATE_NONCE, + PSA_AEAD_SET_NONCE, + PSA_AEAD_SET_LENGTHS, + PSA_AEAD_UPDATE_AD, + PSA_AEAD_UPDATE, + PSA_AEAD_FINISH, + PSA_AEAD_VERIFY, + PSA_AEAD_ABORT, + PSA_SIGN_HASH, + PSA_VERIFY_HASH, + PSA_ASYMMETRIC_ENCRYPT, + PSA_ASYMMETRIC_DECRYPT, + PSA_KEY_DERIVATION_SETUP, + PSA_KEY_DERIVATION_GET_CAPACITY, + PSA_KEY_DERIVATION_SET_CAPACITY, + PSA_KEY_DERIVATION_INPUT_BYTES, + PSA_KEY_DERIVATION_INPUT_KEY, + PSA_KEY_DERIVATION_KEY_AGREEMENT, + PSA_KEY_DERIVATION_OUTPUT_BYTES, + PSA_KEY_DERIVATION_OUTPUT_KEY, + PSA_KEY_DERIVATION_ABORT, + PSA_RAW_KEY_AGREEMENT, + PSA_GENERATE_RANDOM, + PSA_GENERATE_KEY, +} psa_sec_function_t; + +/**@}*/ + +/** \defgroup PSA Crypto structures for IPC +* @{ +*/ + +/** psa_crypto_ipc_s struct used for some of the + * PSA Crypto APIs that need psa_key_handle_t and psa_algorithm_t arguments + * and in order to use the existing infrastructure of the SPM-IPC we provide a struct to + * pack them together. + */ +typedef struct psa_crypto_ipc_s { + psa_sec_function_t func; + psa_key_handle_t handle; + psa_algorithm_t alg; +} psa_crypto_ipc_t; + +/** psa_crypto_derivation_ipc_s struct used for some of the + * PSA Crypto APIs that need psa_key_handle_t and psa_algorithm_t arguments + * and in order to use the existing infrastructure of the SPM-IPC we provide a struct to + * pack them together. + */ +typedef struct psa_crypto_derivation_ipc_s { + psa_sec_function_t func; + psa_key_handle_t handle; + psa_algorithm_t alg; + size_t capacity; +} psa_crypto_derivation_ipc_t; + +/** psa_key_mng_ipc_s struct used for some of the + * PSA Crypto APIs that need psa_key_handle_t and psa_algorithm_t arguments + * and in order to use the existing infrastructure of the SPM-IPC we provide a struct to + * pack them together. + */ +typedef struct psa_key_mng_ipc_s { + psa_key_handle_t handle; + psa_sec_function_t func; +} psa_key_mng_ipc_t; + +/** psa_crypto_ipc_aead_s struct used for AEAD integrated + * PSA Crypto APIs that need psa_key_handle_t and psa_algorithm_t and extra arguments + * and in order to use the existing infrastructure of the SPM-IPC we provide a struct to + * pack them together. + */ +// Max length supported for nonce is 16 bytes. +#define PSA_AEAD_MAX_NONCE_SIZE 16 +typedef struct psa_crypto_ipc_aead_s { + psa_sec_function_t func; + psa_key_handle_t handle; + psa_algorithm_t alg; + uint16_t nonce_size; + size_t additional_data_length; + size_t input_length; + uint8_t nonce[PSA_AEAD_MAX_NONCE_SIZE]; +} psa_crypto_ipc_aead_t; + +/** psa_crypto_ipc_asymmetric_s struct used for asymmetric + * PSA Crypto APIs that need psa_key_handle_t and psa_algorithm_t arguments + * and in order to use the existing infrastructure of the SPM-IPC we provide a struct to + * pack them together. + */ +typedef struct psa_crypto_ipc_asymmetric_s { + psa_sec_function_t func; + psa_key_handle_t handle; + psa_algorithm_t alg; + size_t input_length; + size_t salt_length; +} psa_crypto_ipc_asymmetric_t; + +/**@}*/ + +#endif /* PSA_CRYPTO_SPE_PLATFORM_H */ diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/crypto/COMPONENT_PSA_SRV_IPC/crypto_struct.h b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/crypto/COMPONENT_PSA_SRV_IPC/crypto_struct.h new file mode 100644 index 0000000..465ccbb --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/crypto/COMPONENT_PSA_SRV_IPC/crypto_struct.h @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2020, Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "crypto_struct_ipc.h" diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/crypto/COMPONENT_PSA_SRV_IPC/crypto_struct_ipc.h b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/crypto/COMPONENT_PSA_SRV_IPC/crypto_struct_ipc.h new file mode 100644 index 0000000..20bea21 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/crypto/COMPONENT_PSA_SRV_IPC/crypto_struct_ipc.h @@ -0,0 +1,318 @@ +/** + * \file psa/crypto_struct.h + * + * \brief PSA cryptography module: Mbed TLS structured type implementations + * + * \note This file may not be included directly. Applications must + * include psa/crypto.h. + * + * This file contains the definitions of some data structures with + * implementation-specific definitions. + * + * In implementations with isolation between the application and the + * cryptography module, it is expected that the front-end and the back-end + * would have different versions of this file. + * + *

Design notes about multipart operation structures

+ * + * Each multipart operation structure contains a `psa_algorithm_t alg` + * field which indicates which specific algorithm the structure is for. + * When the structure is not in use, `alg` is 0. Most of the structure + * consists of a union which is discriminated by `alg`. + * + * Note that when `alg` is 0, the content of other fields is undefined. + * In particular, it is not guaranteed that a freshly-initialized structure + * is all-zero: we initialize structures to something like `{0, 0}`, which + * is only guaranteed to initializes the first member of the union; + * GCC and Clang initialize the whole structure to 0 (at the time of writing), + * but MSVC and CompCert don't. + * + * In Mbed Crypto, multipart operation structures live independently from + * the key. This allows Mbed Crypto to free the key objects when destroying + * a key slot. If a multipart operation needs to remember the key after + * the setup function returns, the operation structure needs to contain a + * copy of the key. + */ +/* + * Copyright (C) 2018, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#ifndef PSA_CRYPTO_STRUCT_H +#define PSA_CRYPTO_STRUCT_H + +#include "psa/client.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct psa_hash_operation_s { + psa_handle_t handle; +}; + +#define PSA_HASH_OPERATION_INIT { PSA_NULL_HANDLE } +static inline struct psa_hash_operation_s psa_hash_operation_init( void ) +{ + const struct psa_hash_operation_s v = PSA_HASH_OPERATION_INIT; + return( v ); +} + +struct psa_mac_operation_s +{ + psa_handle_t handle; +}; + +#define PSA_MAC_OPERATION_INIT { PSA_NULL_HANDLE } +static inline struct psa_mac_operation_s psa_mac_operation_init( void ) +{ + const struct psa_mac_operation_s v = PSA_MAC_OPERATION_INIT; + return( v ); +} + +struct psa_cipher_operation_s +{ + psa_handle_t handle; +}; + +#define PSA_CIPHER_OPERATION_INIT { PSA_NULL_HANDLE } +static inline struct psa_cipher_operation_s psa_cipher_operation_init( void ) +{ + const struct psa_cipher_operation_s v = PSA_CIPHER_OPERATION_INIT; + return( v ); +} + +struct psa_aead_operation_s +{ + psa_handle_t handle; +}; + +#define PSA_AEAD_OPERATION_INIT { PSA_NULL_HANDLE } +static inline struct psa_aead_operation_s psa_aead_operation_init( void ) +{ + const struct psa_aead_operation_s v = PSA_AEAD_OPERATION_INIT; + return( v ); +} + +struct psa_key_derivation_s +{ + psa_handle_t handle; +}; + +/* This only zeroes out the first byte in the union, the rest is unspecified. */ +#define PSA_KEY_DERIVATION_OPERATION_INIT { PSA_NULL_HANDLE } +static inline struct psa_key_derivation_s psa_key_derivation_operation_init( void ) +{ + const struct psa_key_derivation_s v = PSA_KEY_DERIVATION_OPERATION_INIT; + return( v ); +} + +struct psa_key_policy_s +{ + psa_key_usage_t usage; + psa_algorithm_t alg; + psa_algorithm_t alg2; +}; +typedef struct psa_key_policy_s psa_key_policy_t; + +#define PSA_KEY_POLICY_INIT {0, 0, 0} +static inline struct psa_key_policy_s psa_key_policy_init( void ) +{ + const struct psa_key_policy_s v = PSA_KEY_POLICY_INIT; + return( v ); +} + +/* The type used internally for key sizes. + * Public interfaces use size_t, but internally we use a smaller type. */ +typedef uint16_t psa_key_bits_t; +/* The maximum value of the type used to represent bit-sizes. + * This is used to mark an invalid key size. */ +#define PSA_KEY_BITS_TOO_LARGE ( (psa_key_bits_t) ( -1 ) ) +/* The maximum size of a key in bits. + * Currently defined as the maximum that can be represented, rounded down + * to a whole number of bytes. + * This is an uncast value so that it can be used in preprocessor + * conditionals. */ +#define PSA_MAX_KEY_BITS 0xfff8 + +/** A mask of flags that can be stored in key attributes. + * + * This type is also used internally to store flags in slots. Internal + * flags are defined in library/psa_crypto_core.h. Internal flags may have + * the same value as external flags if they are properly handled during + * key creation and in psa_get_key_attributes. + */ +typedef uint16_t psa_key_attributes_flag_t; + +#define MBEDTLS_PSA_KA_FLAG_HAS_SLOT_NUMBER \ + ( (psa_key_attributes_flag_t) 0x0001 ) + +/* A mask of key attribute flags used externally only. + * Only meant for internal checks inside the library. */ +#define MBEDTLS_PSA_KA_MASK_EXTERNAL_ONLY ( \ + MBEDTLS_PSA_KA_FLAG_HAS_SLOT_NUMBER | \ + 0 ) + +/* A mask of key attribute flags used both internally and externally. + * Currently there aren't any. */ +#define MBEDTLS_PSA_KA_MASK_DUAL_USE ( \ + 0 ) + +typedef struct +{ + psa_key_type_t type; + psa_key_lifetime_t lifetime; + psa_key_id_t id; + psa_key_policy_t policy; + psa_key_bits_t bits; + psa_key_attributes_flag_t flags; +} psa_core_key_attributes_t; + +#define PSA_CORE_KEY_ATTRIBUTES_INIT {0, 0, PSA_KEY_ID_INIT, PSA_KEY_POLICY_INIT, 0, 0} + +struct psa_key_attributes_s +{ + psa_core_key_attributes_t core; +#if defined(MBEDTLS_PSA_CRYPTO_SE_C) + psa_key_slot_number_t slot_number; +#endif /* MBEDTLS_PSA_CRYPTO_SE_C */ + void *domain_parameters; + size_t domain_parameters_size; +}; + +#if defined(MBEDTLS_PSA_CRYPTO_SE_C) +#define PSA_KEY_ATTRIBUTES_INIT {PSA_CORE_KEY_ATTRIBUTES_INIT, 0, NULL, 0} +#else +#define PSA_KEY_ATTRIBUTES_INIT {PSA_CORE_KEY_ATTRIBUTES_INIT, NULL, 0} +#endif + +static inline struct psa_key_attributes_s psa_key_attributes_init( void ) +{ + const struct psa_key_attributes_s v = PSA_KEY_ATTRIBUTES_INIT; + return( v ); +} + +static inline void psa_set_key_id(psa_key_attributes_t *attributes, + psa_key_id_t id) +{ + attributes->core.id = id; + if( attributes->core.lifetime == PSA_KEY_LIFETIME_VOLATILE ) + attributes->core.lifetime = PSA_KEY_LIFETIME_PERSISTENT; +} + +static inline psa_key_id_t psa_get_key_id( + const psa_key_attributes_t *attributes) +{ + return( attributes->core.id ); +} + +static inline void psa_set_key_lifetime(psa_key_attributes_t *attributes, + psa_key_lifetime_t lifetime) +{ + attributes->core.lifetime = lifetime; + if( lifetime == PSA_KEY_LIFETIME_VOLATILE ) + { +#ifdef MBEDTLS_PSA_CRYPTO_KEY_FILE_ID_ENCODES_OWNER + attributes->core.id.key_id = 0; + attributes->core.id.owner = 0; +#else + attributes->core.id = 0; +#endif + } +} + +static inline psa_key_lifetime_t psa_get_key_lifetime( + const psa_key_attributes_t *attributes) +{ + return( attributes->core.lifetime ); +} + +static inline void psa_set_key_usage_flags(psa_key_attributes_t *attributes, + psa_key_usage_t usage_flags) +{ + attributes->core.policy.usage = usage_flags; +} + +static inline psa_key_usage_t psa_get_key_usage_flags( + const psa_key_attributes_t *attributes) +{ + return( attributes->core.policy.usage ); +} + +static inline void psa_set_key_algorithm(psa_key_attributes_t *attributes, + psa_algorithm_t alg) +{ + attributes->core.policy.alg = alg; +} + +static inline psa_algorithm_t psa_get_key_algorithm( + const psa_key_attributes_t *attributes) +{ + return( attributes->core.policy.alg ); +} + +/* This function is declared in crypto_extra.h, which comes after this + * header file, but we need the function here, so repeat the declaration. */ +psa_status_t psa_set_key_domain_parameters(psa_key_attributes_t *attributes, + psa_key_type_t type, + const uint8_t *data, + size_t data_length); + +static inline void psa_set_key_type(psa_key_attributes_t *attributes, + psa_key_type_t type) +{ + if( attributes->domain_parameters == NULL ) + { + /* Common case: quick path */ + attributes->core.type = type; + } + else + { + /* Call the bigger function to free the old domain paramteres. + * Ignore any errors which may arise due to type requiring + * non-default domain parameters, since this function can't + * report errors. */ + (void) psa_set_key_domain_parameters( attributes, type, NULL, 0 ); + } +} + +static inline psa_key_type_t psa_get_key_type( + const psa_key_attributes_t *attributes) +{ + return( attributes->core.type ); +} + +static inline void psa_set_key_bits(psa_key_attributes_t *attributes, + size_t bits) +{ + if( bits > PSA_MAX_KEY_BITS ) + attributes->core.bits = PSA_KEY_BITS_TOO_LARGE; + else + attributes->core.bits = (psa_key_bits_t) bits; +} + +static inline size_t psa_get_key_bits( + const psa_key_attributes_t *attributes) +{ + return( attributes->core.bits ); +} + +#ifdef __cplusplus +} +#endif + +#endif /* PSA_CRYPTO_STRUCT_H */ diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/crypto/COMPONENT_PSA_SRV_IPC/psa_crypto_spm.c b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/crypto/COMPONENT_PSA_SRV_IPC/psa_crypto_spm.c new file mode 100644 index 0000000..c50004a --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/crypto/COMPONENT_PSA_SRV_IPC/psa_crypto_spm.c @@ -0,0 +1,1636 @@ +/* + * PSA crypto layer on top of Mbed TLS crypto + */ +/* Copyright (C) 2018, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_PSA_CRYPTO_C) + +#include +#include +#include + +#include "psa_manifest/sid.h" +#include "psa/client.h" +#include "psa/crypto.h" +#include "crypto_platform_spe.h" +#include "mbed_assert.h" + +#define MINOR_VER 1 +#define CLIENT_PSA_KEY_ID_SIZE_IN_BYTES 4 + +MBED_STATIC_ASSERT(sizeof(psa_key_id_t) == CLIENT_PSA_KEY_ID_SIZE_IN_BYTES, "Unexpected psa_key_id_t size"); + +/****************************************************************/ +/* INTERNAL HELPER FUNCTIONS */ +/****************************************************************/ +static psa_status_t ipc_connect(uint32_t sid, psa_handle_t *handle) +{ + *handle = psa_connect(sid, MINOR_VER); + if (*handle <= PSA_NULL_HANDLE) { + return (PSA_ERROR_COMMUNICATION_FAILURE); + } + return (PSA_SUCCESS); +} + +static inline void ipc_close(psa_handle_t *handle) +{ + psa_close(*handle); + *handle = PSA_NULL_HANDLE; +} + +static psa_status_t ipc_call(psa_handle_t *handle, psa_invec *in_vec, size_t in_vec_size, + psa_outvec *out_vec, size_t out_vec_size, bool close) +{ + if (*handle <= PSA_NULL_HANDLE) { + return (PSA_ERROR_BAD_STATE); + } + + psa_status_t status = psa_call(*handle, in_vec, in_vec_size, out_vec, out_vec_size); + if (close) { + ipc_close(handle); + } + return (status); +} + +static psa_status_t ipc_oneshot(uint32_t sid, psa_invec *in_vec, size_t in_vec_size, + psa_outvec *out_vec, size_t out_vec_size) +{ + psa_handle_t handle = PSA_NULL_HANDLE; + psa_status_t status = ipc_connect(sid, &handle); + if (status != PSA_SUCCESS) { + return status; + } + status = ipc_call(&handle, in_vec, in_vec_size, out_vec, out_vec_size, true); + return (status); +} + + +/* + * PSA Crypto API (crypto.h) + */ + +psa_status_t psa_crypto_init(void) +{ + psa_status_t status = ipc_oneshot(PSA_CRYPTO_INIT_ID, NULL, 0, NULL, 0); + return (status); +} + +psa_status_t psa_get_key_attributes(psa_key_handle_t handle, + psa_key_attributes_t *attributes) +{ + psa_key_mng_ipc_t psa_key_mng_ipc = { + .func = PSA_GET_KEY_ATTRIBUTES, + .handle = handle + }; + + psa_invec in_vec = { &psa_key_mng_ipc, sizeof(psa_key_mng_ipc) }; + + psa_outvec out_vec = { attributes, sizeof(*attributes) }; + + return ipc_oneshot(PSA_KEY_MNG_ID, &in_vec, 1, &out_vec, 1); +} + +void psa_reset_key_attributes(psa_key_attributes_t *attributes) +{ + /* The reset of key attributes can happen entirely without going to the + * core. In fact, it can't go to the core without causing issues with + * memory ownership. Given that psa_set_key_domain_parameters(), which we + * currently don't allow in the client/server architecture, allocates + * memory that would be freed by psa_reset_key_attributes(), we must do + * this in the NSPE due to lack of memory ownership information in the + * core; the SPE can't currently know if any given allocation is valid to + * free for a given client. */ + + /* Note attributes->domain_parameters are currently ignored, as we don't + * currently support them in client/server architecture. */ + memset(attributes, 0, sizeof(*attributes)); +} + +psa_status_t psa_set_key_domain_parameters(psa_key_attributes_t *attributes, + psa_key_type_t type, + const uint8_t *data, + size_t data_length) +{ + return PSA_ERROR_NOT_SUPPORTED; +} + +psa_status_t psa_get_key_domain_parameters(const psa_key_attributes_t *attributes, + uint8_t *data, + size_t data_size, + size_t *data_length) +{ + return PSA_ERROR_NOT_SUPPORTED; +} + +psa_status_t psa_open_key(psa_key_id_t id, + psa_key_handle_t *handle) +{ + psa_key_mng_ipc_t psa_key_mng_ipc = { + .func = PSA_OPEN_KEY, + .handle = *handle, + }; + + psa_invec in_vec[2] = { + { &psa_key_mng_ipc, sizeof(psa_key_mng_ipc) }, + { &id, sizeof(id) } + }; + + psa_outvec out_vec = { handle, sizeof(*handle) }; + + psa_status_t status = ipc_oneshot(PSA_KEY_MNG_ID, in_vec, 2, &out_vec, 1); + return (status); +} + +psa_status_t psa_close_key(psa_key_handle_t handle) +{ + psa_key_mng_ipc_t psa_key_mng_ipc = { + .func = PSA_CLOSE_KEY, + .handle = handle, + }; + + psa_invec in_vec = { &psa_key_mng_ipc, sizeof(psa_key_mng_ipc) }; + + psa_status_t status = ipc_oneshot(PSA_KEY_MNG_ID, &in_vec, 1, NULL, 0); + return (status); +} + +psa_status_t psa_import_key(const psa_key_attributes_t *attributes, + const uint8_t *data, + size_t data_length, + psa_key_handle_t *handle) +{ + psa_key_mng_ipc_t psa_key_mng_ipc = { + .func = PSA_IMPORT_KEY, + .handle = 0, + }; + + psa_invec in_vec[3] = { + { &psa_key_mng_ipc, sizeof(psa_key_mng_ipc) }, + { attributes, sizeof(*attributes) }, + { data, data_length }, + }; + + psa_outvec out_vec = { handle, sizeof(*handle) }; + + return ipc_oneshot(PSA_KEY_MNG_ID, in_vec, 3, &out_vec, 1); +} + +psa_status_t psa_destroy_key(psa_key_handle_t handle) +{ + psa_key_mng_ipc_t psa_key_mng_ipc = { + .func = PSA_DESTROY_KEY, + .handle = handle, + }; + + psa_invec in_vec = { &psa_key_mng_ipc, sizeof(psa_key_mng_ipc) }; + + psa_status_t status = ipc_oneshot(PSA_KEY_MNG_ID, &in_vec, 1, NULL, 0); + return (status); +} + +static psa_status_t psa_export_key_common(psa_key_handle_t handle, + uint8_t *data, + size_t data_size, + size_t *data_length, + psa_sec_function_t func) +{ + psa_key_mng_ipc_t psa_key_mng_ipc = { + .func = func, + .handle = handle, + }; + + psa_invec in_vec = { &psa_key_mng_ipc, sizeof(psa_key_mng_ipc) }; + + psa_outvec out_vec[2] = { + { data, data_size }, + { data_length, sizeof(*data_length) } + }; + + psa_status_t status = ipc_oneshot(PSA_KEY_MNG_ID, &in_vec, 1, out_vec, 2); + return (status); +} + +psa_status_t psa_export_key(psa_key_handle_t handle, + uint8_t *data, + size_t data_size, + size_t *data_length) +{ + psa_status_t status = psa_export_key_common(handle, data, data_size, + data_length, PSA_EXPORT_KEY); + return (status); +} + +psa_status_t psa_export_public_key(psa_key_handle_t handle, + uint8_t *data, + size_t data_size, + size_t *data_length) +{ + psa_status_t status = psa_export_key_common(handle, data, data_size, + data_length, + PSA_EXPORT_PUBLIC_KEY); + return (status); +} + +psa_status_t psa_copy_key(psa_key_handle_t source_handle, + const psa_key_attributes_t *attributes, + psa_key_handle_t *target_handle) +{ + psa_key_mng_ipc_t psa_key_mng_ipc = { + .func = PSA_COPY_KEY, + .handle = source_handle, + }; + + psa_invec in_vec = { &psa_key_mng_ipc, sizeof(psa_key_mng_ipc) }; + + psa_outvec out_vec = { target_handle, sizeof(*target_handle) }; + + return ipc_oneshot(PSA_KEY_MNG_ID, &in_vec, 1, &out_vec, 1); +} + +psa_status_t psa_hash_compute(psa_algorithm_t alg, + const uint8_t *input, + size_t input_length, + uint8_t *hash, + size_t hash_size, + size_t *hash_length) +{ + psa_crypto_ipc_t psa_crypto_ipc = { + .func = PSA_HASH_COMPUTE, + .handle = 0, + .alg = alg, + }; + + psa_invec in_vec[2] = { + { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }, + { input, input_length } + }; + + psa_outvec out_vec[2] = { + { hash, hash_size }, + { hash_length, sizeof(*hash_length) } + }; + + return ipc_oneshot(PSA_HASH_ID, in_vec, 2, out_vec, 2); +} + +psa_status_t psa_hash_compare(psa_algorithm_t alg, + const uint8_t *input, + size_t input_length, + const uint8_t *hash, + const size_t hash_length) +{ + psa_crypto_ipc_t psa_crypto_ipc = { + .func = PSA_HASH_COMPARE, + .handle = 0, + .alg = alg, + }; + + psa_invec in_vec[3] = { + { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }, + { input, input_length }, + { hash, hash_length }, + }; + + return ipc_oneshot(PSA_HASH_ID, in_vec, 3, NULL, 0); +} + +psa_status_t psa_hash_setup(psa_hash_operation_t *operation, + psa_algorithm_t alg) +{ + if (operation->handle != PSA_NULL_HANDLE) { + return (PSA_ERROR_BAD_STATE); + } + + psa_crypto_ipc_t psa_crypto_ipc = { + .func = PSA_HASH_SETUP, + .handle = 0, + .alg = alg + }; + + psa_invec in_vec = { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }; + + psa_status_t status = ipc_connect(PSA_HASH_ID, &operation->handle); + if (status != PSA_SUCCESS) { + return (status); + } + status = ipc_call(&operation->handle, &in_vec, 1, NULL, 0, false); + if (status != PSA_SUCCESS) { + ipc_close(&operation->handle); + } + return (status); +} + +psa_status_t psa_hash_update(psa_hash_operation_t *operation, + const uint8_t *input, + size_t input_length) +{ + psa_crypto_ipc_t psa_crypto_ipc = { + .func = PSA_HASH_UPDATE, + .handle = 0, + .alg = 0 + }; + + psa_invec in_vec[2] = { + { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }, + { input, input_length } + }; + + psa_status_t status = ipc_call(&operation->handle, in_vec, 2, NULL, 0, false); + if (status != PSA_SUCCESS) { + ipc_close(&operation->handle); + } + return (status); +} + +psa_status_t psa_hash_finish(psa_hash_operation_t *operation, + uint8_t *hash, + size_t hash_size, + size_t *hash_length) +{ + psa_crypto_ipc_t psa_crypto_ipc = { + .func = PSA_HASH_FINISH, + .handle = 0, + .alg = 0 + }; + + psa_invec in_vec[2] = { + { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }, + { &hash_size, sizeof(hash_size) } + }; + + psa_outvec out_vec[2] = { + { hash, hash_size }, + { hash_length, sizeof(*hash_length) } + }; + + psa_status_t status = ipc_call(&operation->handle, in_vec, 2, out_vec, 2, true); + return (status); +} + +psa_status_t psa_hash_verify(psa_hash_operation_t *operation, + const uint8_t *hash, + size_t hash_length) +{ + psa_crypto_ipc_t psa_crypto_ipc = { + .func = PSA_HASH_VERIFY, + .handle = 0, + .alg = 0 + }; + + psa_invec in_vec[3] = { + { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }, + { &hash_length, sizeof(hash_length) }, + { hash, hash_length } + }; + + psa_status_t status = ipc_call(&operation->handle, in_vec, 3, NULL, 0, true); + return (status); +} + +psa_status_t psa_hash_abort(psa_hash_operation_t *operation) +{ + if (operation->handle <= PSA_NULL_HANDLE) { + return (PSA_SUCCESS); + } + + psa_crypto_ipc_t psa_crypto_ipc = { + .func = PSA_HASH_ABORT, + .handle = 0, + .alg = 0 + }; + + psa_invec in_vec = { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }; + + psa_status_t status = ipc_call(&operation->handle, &in_vec, 1, NULL, 0, true); + return (status); +} + +psa_status_t psa_hash_clone(const psa_hash_operation_t *source_operation, + psa_hash_operation_t *target_operation) +{ + if (source_operation->handle <= PSA_NULL_HANDLE || target_operation->handle != PSA_NULL_HANDLE) { + return (PSA_ERROR_BAD_STATE); + } + + psa_crypto_ipc_t psa_crypto_ipc = { + .func = 0, + .handle = 0, + .alg = 0 + }; + + size_t index = 0; + + psa_invec in_vec[2] = { + { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }, + { &index, sizeof(index) } + }; + + psa_outvec out_vec = { &index, sizeof(index) }; + + psa_status_t status = ipc_connect(PSA_HASH_ID, &target_operation->handle); + if (status != PSA_SUCCESS) { + return (status); + } + + psa_crypto_ipc.func = PSA_HASH_CLONE_BEGIN; + status = ipc_call((psa_handle_t *)&source_operation->handle, in_vec, 1, &out_vec, 1, false); + if (status != PSA_SUCCESS) { + goto exit; + } + + psa_crypto_ipc.func = PSA_HASH_CLONE_END; + status = ipc_call(&target_operation->handle, in_vec, 2, NULL, 0, false); + +exit: + if (status != PSA_SUCCESS) { + ipc_close(&target_operation->handle); + } + return (status); +} + +psa_status_t psa_mac_compute(psa_key_handle_t handle, + psa_algorithm_t alg, + const uint8_t *input, + size_t input_length, + uint8_t *mac, + size_t mac_size, + size_t *mac_length) +{ + psa_crypto_ipc_t psa_crypto_ipc = { + .func = PSA_MAC_COMPUTE, + .handle = handle, + .alg = alg, + }; + + psa_invec in_vec[2] = { + { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }, + { input, input_length }, + }; + + psa_outvec out_vec[2] = { + { mac, mac_size }, + { mac_length, sizeof(*mac_length) }, + }; + + psa_status_t status = ipc_oneshot(PSA_MAC_ID, in_vec, 2, out_vec, 2); + return (status); +} + +psa_status_t psa_mac_verify(psa_key_handle_t handle, + psa_algorithm_t alg, + const uint8_t *input, + size_t input_length, + const uint8_t *mac, + const size_t mac_length) +{ + psa_crypto_ipc_t psa_crypto_ipc = { + .func = PSA_MAC_VERIFY, + .handle = handle, + .alg = alg, + }; + + psa_invec in_vec[3] = { + { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }, + { input, input_length }, + { mac, mac_length }, + }; + + psa_status_t status = ipc_oneshot(PSA_MAC_ID, in_vec, 2, NULL, 0); + return (status); +} + +static psa_status_t psa_mac_setup(psa_mac_operation_t *operation, + psa_key_handle_t handle, + psa_algorithm_t alg, + psa_sec_function_t func) +{ + if (operation->handle != PSA_NULL_HANDLE) { + return (PSA_ERROR_BAD_STATE); + } + + psa_crypto_ipc_t psa_crypto_ipc = { + .func = func, + .handle = handle, + .alg = alg + }; + + psa_invec in_vec = { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }; + + psa_status_t status = ipc_connect(PSA_MAC_ID, &operation->handle); + if (status != PSA_SUCCESS) { + return (status); + } + status = ipc_call(&operation->handle, &in_vec, 1, NULL, 0, false); + if (status != PSA_SUCCESS) { + ipc_close(&operation->handle); + } + return (status); +} + +psa_status_t psa_mac_sign_setup(psa_mac_operation_t *operation, + psa_key_handle_t handle, + psa_algorithm_t alg) +{ + psa_status_t status = psa_mac_setup(operation, handle, alg, PSA_MAC_SIGN_SETUP); + return (status); +} + +psa_status_t psa_mac_verify_setup(psa_mac_operation_t *operation, + psa_key_handle_t handle, + psa_algorithm_t alg) +{ + psa_status_t status = psa_mac_setup(operation, handle, alg, PSA_MAC_VERIFY_SETUP); + return (status); +} + +psa_status_t psa_mac_update(psa_mac_operation_t *operation, + const uint8_t *input, + size_t input_length) +{ + psa_crypto_ipc_t psa_crypto_ipc = { + .func = PSA_MAC_UPDATE, + .handle = 0, + .alg = 0 + }; + + psa_invec in_vec[2] = { + { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }, + { input, input_length } + }; + + psa_status_t status = ipc_call(&operation->handle, in_vec, 2, NULL, 0, false); + if (status != PSA_SUCCESS) { + ipc_close(&operation->handle); + } + return (status); +} + +psa_status_t psa_mac_sign_finish(psa_mac_operation_t *operation, + uint8_t *mac, + size_t mac_size, + size_t *mac_length) +{ + psa_crypto_ipc_t psa_crypto_ipc = { + .func = PSA_MAC_SIGN_FINISH, + .handle = 0, + .alg = 0 + }; + + psa_invec in_vec[2] = { + { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }, + { &mac_size, sizeof(mac_size) } + }; + + psa_outvec out_vec[2] = { + { mac, mac_size }, + { mac_length, sizeof(*mac_length) } + }; + + psa_status_t status = ipc_call(&operation->handle, in_vec, 2, out_vec, 2, true); + return (status); +} + +psa_status_t psa_mac_verify_finish(psa_mac_operation_t *operation, + const uint8_t *mac, + size_t mac_length) +{ + psa_crypto_ipc_t psa_crypto_ipc = { + .func = PSA_MAC_VERIFY_FINISH, + .handle = 0, + .alg = 0 + }; + + psa_invec in_vec[3] = { + { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }, + { &mac_length, sizeof(mac_length) }, + { mac, mac_length } + }; + + psa_status_t status = ipc_call(&operation->handle, in_vec, 3, NULL, 0, true); + return (status); +} + +psa_status_t psa_mac_abort(psa_mac_operation_t *operation) +{ + if (operation->handle <= PSA_NULL_HANDLE) { + return (PSA_SUCCESS); + } + + psa_crypto_ipc_t psa_crypto_ipc = { + .func = PSA_MAC_ABORT, + .handle = 0, + .alg = 0 + }; + + psa_invec in_vec = { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }; + + psa_status_t status = ipc_call(&operation->handle, &in_vec, 1, NULL, 0, true); + return (status); +} + +psa_status_t psa_cipher_encrypt(psa_key_handle_t handle, + psa_algorithm_t alg, + const uint8_t *input, + size_t input_length, + uint8_t *output, + size_t output_size, + size_t *output_length) +{ + psa_crypto_ipc_t psa_crypto_ipc = { + .func = PSA_CIPHER_ENCRYPT, + .handle = handle, + .alg = alg, + }; + + psa_invec in_vec[2] = { + { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }, + { input, input_length }, + }; + + psa_outvec out_vec[2] = { + { output, output_size }, + { output_length, sizeof(*output_length) }, + }; + + psa_status_t status = ipc_oneshot(PSA_SYMMETRIC_ID, in_vec, 2, out_vec, 2); + return (status); +} + +psa_status_t psa_cipher_decrypt(psa_key_handle_t handle, + psa_algorithm_t alg, + const uint8_t *input, + size_t input_length, + uint8_t *output, + size_t output_size, + size_t *output_length) +{ + psa_crypto_ipc_t psa_crypto_ipc = { + .func = PSA_CIPHER_DECRYPT, + .handle = handle, + .alg = alg, + }; + + psa_invec in_vec[3] = { + { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }, + { input, input_length }, + }; + + psa_outvec out_vec[2] = { + { output, output_size }, + { output_length, sizeof(*output_length) }, + }; + + psa_status_t status = ipc_oneshot(PSA_SYMMETRIC_ID, in_vec, 2, out_vec, 2); + return (status); +} + +static psa_status_t psa_cipher_setup(psa_cipher_operation_t *operation, + psa_key_handle_t handle, + psa_algorithm_t alg, + psa_sec_function_t func) +{ + if (operation->handle != PSA_NULL_HANDLE) { + return (PSA_ERROR_BAD_STATE); + } + + psa_crypto_ipc_t psa_crypto_ipc = { + .func = func, + .handle = handle, + .alg = alg + }; + + psa_invec in_vec = { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }; + + psa_status_t status = ipc_connect(PSA_SYMMETRIC_ID, &operation->handle); + if (status != PSA_SUCCESS) { + return (status); + } + status = ipc_call(&operation->handle, &in_vec, 1, NULL, 0, false); + if (status != PSA_SUCCESS) { + ipc_close(&operation->handle); + } + return (status); +} + +psa_status_t psa_cipher_encrypt_setup(psa_cipher_operation_t *operation, + psa_key_handle_t handle, + psa_algorithm_t alg) +{ + psa_status_t status = psa_cipher_setup(operation, handle, alg, PSA_CIPHER_ENCRYPT_SETUP); + return (status); +} + +psa_status_t psa_cipher_decrypt_setup(psa_cipher_operation_t *operation, + psa_key_handle_t handle, + psa_algorithm_t alg) +{ + psa_status_t status = psa_cipher_setup(operation, handle, alg, PSA_CIPHER_DECRYPT_SETUP); + return (status); +} + +psa_status_t psa_cipher_generate_iv(psa_cipher_operation_t *operation, + uint8_t *iv, + size_t iv_size, + size_t *iv_length) +{ + psa_crypto_ipc_t psa_crypto_ipc = { + .func = PSA_CIPHER_GENERATE_IV, + .handle = 0, + .alg = 0 + }; + + psa_invec in_vec = { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }; + + psa_outvec out_vec[2] = { + { iv, iv_size }, + { iv_length, sizeof(*iv_length) } + }; + + psa_status_t status = ipc_call(&operation->handle, &in_vec, 1, out_vec, 2, false); + if (status != PSA_SUCCESS) { + ipc_close(&operation->handle); + } + return (status); +} + +psa_status_t psa_cipher_set_iv(psa_cipher_operation_t *operation, + const uint8_t *iv, + size_t iv_length) +{ + psa_crypto_ipc_t psa_crypto_ipc = { + .func = PSA_CIPHER_SET_IV, + .handle = 0, + .alg = 0 + }; + + psa_invec in_vec[2] = { + { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }, + { iv, iv_length } + }; + + psa_status_t status = ipc_call(&operation->handle, in_vec, 2, NULL, 0, false); + if (status != PSA_SUCCESS) { + ipc_close(&operation->handle); + } + return (status); +} + +psa_status_t psa_cipher_update(psa_cipher_operation_t *operation, + const uint8_t *input, + size_t input_length, + uint8_t *output, + size_t output_size, + size_t *output_length) +{ + psa_crypto_ipc_t psa_crypto_ipc = { + .func = PSA_CIPHER_UPDATE, + .handle = 0, + .alg = 0 + }; + + psa_invec in_vec[2] = { + { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }, + { input, input_length } + }; + + psa_outvec out_vec[2] = { + { output, output_size }, + { output_length, (output_length == NULL ? 0 : sizeof(*output_length)) } + }; + + psa_status_t status = ipc_call(&operation->handle, in_vec, 2, out_vec, 2, false); + if (status != PSA_SUCCESS) { + ipc_close(&operation->handle); + } + return (status); +} + +psa_status_t psa_cipher_finish(psa_cipher_operation_t *operation, + uint8_t *output, + size_t output_size, + size_t *output_length) +{ + psa_crypto_ipc_t psa_crypto_ipc = { + .func = PSA_CIPHER_FINISH, + .handle = 0, + .alg = 0 + }; + + psa_invec in_vec = { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }; + + psa_outvec out_vec[2] = { + { output, output_size }, + { output_length, (output_length == NULL ? 0 : sizeof(*output_length)) } + }; + + psa_status_t status = ipc_call(&operation->handle, &in_vec, 1, out_vec, 2, true); + return (status); +} + +psa_status_t psa_cipher_abort(psa_cipher_operation_t *operation) +{ + if (operation->handle <= PSA_NULL_HANDLE) { + return (PSA_SUCCESS); + } + + psa_crypto_ipc_t psa_crypto_ipc = { + .func = PSA_CIPHER_ABORT, + .handle = 0, + .alg = 0 + }; + + psa_invec in_vec = { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }; + + psa_status_t status = ipc_call(&operation->handle, &in_vec, 1, NULL, 0, true); + return (status); +} + +psa_status_t psa_aead_encrypt(psa_key_handle_t handle, + psa_algorithm_t alg, + const uint8_t *nonce, + size_t nonce_length, + const uint8_t *additional_data, + size_t additional_data_length, + const uint8_t *plaintext, + size_t plaintext_length, + uint8_t *ciphertext, + size_t ciphertext_size, + size_t *ciphertext_length) +{ + if (nonce_length > PSA_AEAD_MAX_NONCE_SIZE) { + return (PSA_ERROR_INVALID_ARGUMENT); + } + + uint8_t *buffer = calloc(1, (additional_data_length + plaintext_length)); + if (buffer == NULL) { + return (PSA_ERROR_INSUFFICIENT_MEMORY); + } + + psa_crypto_ipc_aead_t psa_crypto_ipc = { + .func = PSA_AEAD_ENCRYPT, + .handle = handle, + .alg = alg, + .nonce_size = nonce_length, + .additional_data_length = additional_data_length, + .input_length = plaintext_length, + .nonce = { 0 } + }; + + psa_invec in_vec[2] = { + { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }, + { buffer, (additional_data_length + plaintext_length) } + }; + + psa_outvec out_vec[2] = { + { ciphertext, ciphertext_size }, + { ciphertext_length, sizeof(*ciphertext_length) } + }; + + psa_status_t status; + memcpy(buffer, additional_data, additional_data_length); + memcpy(buffer + additional_data_length, plaintext, plaintext_length); + memcpy(psa_crypto_ipc.nonce, nonce, nonce_length); + + status = ipc_oneshot(PSA_AEAD_ID, in_vec, 2, out_vec, 2); + free(buffer); + return (status); +} + +psa_status_t psa_aead_decrypt(psa_key_handle_t handle, + psa_algorithm_t alg, + const uint8_t *nonce, + size_t nonce_length, + const uint8_t *additional_data, + size_t additional_data_length, + const uint8_t *ciphertext, + size_t ciphertext_length, + uint8_t *plaintext, + size_t plaintext_size, + size_t *plaintext_length) +{ + if (nonce_length > PSA_AEAD_MAX_NONCE_SIZE) { + return (PSA_ERROR_INVALID_ARGUMENT); + } + + uint8_t *buffer = calloc(1, (additional_data_length + ciphertext_length)); + if (buffer == NULL) { + return (PSA_ERROR_INSUFFICIENT_MEMORY); + } + + psa_crypto_ipc_aead_t psa_crypto_ipc = { + .func = PSA_AEAD_DECRYPT, + .handle = handle, + .alg = alg, + .nonce_size = nonce_length, + .additional_data_length = additional_data_length, + .input_length = ciphertext_length, + .nonce = { 0 } + }; + + psa_invec in_vec[2] = { + { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }, + { buffer, (additional_data_length + ciphertext_length) } + }; + + psa_outvec out_vec[2] = { + { plaintext, plaintext_size }, + { plaintext_length, sizeof(*plaintext_length) } + }; + + psa_status_t status; + memcpy(buffer, additional_data, additional_data_length); + memcpy(buffer + additional_data_length, ciphertext, ciphertext_length); + memcpy(psa_crypto_ipc.nonce, nonce, nonce_length); + + status = ipc_oneshot(PSA_AEAD_ID, in_vec, 2, out_vec, 2); + free(buffer); + return (status); +} + +static psa_status_t psa_aead_setup(psa_aead_operation_t *operation, + psa_key_handle_t handle, + psa_algorithm_t alg, + psa_sec_function_t func) +{ + if (operation->handle != PSA_NULL_HANDLE) { + return PSA_ERROR_BAD_STATE; + } + + psa_crypto_ipc_t psa_crypto_ipc = { + .func = func, + .handle = handle, + .alg = alg + }; + + psa_invec in_vec = { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }; + + psa_status_t status = ipc_connect(PSA_AEAD_ID, &operation->handle); + if (status != PSA_SUCCESS) { + return status; + } + status = ipc_call(&operation->handle, &in_vec, 1, NULL, 0, false); + if (status != PSA_SUCCESS) { + ipc_close(&operation->handle); + } + return status; +} + +psa_status_t psa_aead_encrypt_setup(psa_aead_operation_t *operation, + psa_key_handle_t handle, + psa_algorithm_t alg) +{ + return psa_aead_setup(operation, handle, alg, PSA_AEAD_ENCRYPT_SETUP); +} + +psa_status_t psa_aead_decrypt_setup(psa_aead_operation_t *operation, + psa_key_handle_t handle, + psa_algorithm_t alg) +{ + return psa_aead_setup(operation, handle, alg, PSA_AEAD_DECRYPT_SETUP); +} + +psa_status_t psa_aead_generate_nonce(psa_aead_operation_t *operation, + uint8_t *nonce, + size_t nonce_size, + size_t *nonce_length) +{ + if (operation->handle <= PSA_NULL_HANDLE) { + return PSA_ERROR_BAD_STATE; + } + + psa_crypto_ipc_aead_t psa_crypto_ipc = { + .func = PSA_AEAD_GENERATE_NONCE, + .handle = 0, + }; + + psa_invec in_vec[1] = { + { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }, + }; + + psa_outvec out_vec[2] = { + { nonce, nonce_size }, + { nonce_length, sizeof(*nonce_length) }, + }; + + return ipc_call(&operation->handle, in_vec, 1, out_vec, 2, false); +} + +psa_status_t psa_aead_set_nonce(psa_aead_operation_t *operation, + const uint8_t *nonce, + size_t nonce_length) +{ + if (operation->handle <= PSA_NULL_HANDLE) { + return PSA_ERROR_BAD_STATE; + } + + if (nonce_length > PSA_AEAD_MAX_NONCE_SIZE) { + return (PSA_ERROR_INVALID_ARGUMENT); + } + + psa_crypto_ipc_aead_t psa_crypto_ipc = { + .func = PSA_AEAD_SET_NONCE, + .handle = 0, + }; + + psa_invec in_vec[2] = { + { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }, + { nonce, nonce_length } + }; + + return ipc_call(&operation->handle, in_vec, 2, NULL, 0, false); +} + +psa_status_t psa_aead_set_lengths(psa_aead_operation_t *operation, + size_t ad_length, + size_t plaintext_length) +{ + if (operation->handle <= PSA_NULL_HANDLE) { + return PSA_ERROR_BAD_STATE; + } + + psa_crypto_ipc_aead_t psa_crypto_ipc = { + .func = PSA_AEAD_SET_LENGTHS, + .handle = 0, + .alg = 0, + .additional_data_length = ad_length, + .input_length = plaintext_length, + }; + + psa_invec in_vec[1] = { + { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }, + }; + + return ipc_call(&operation->handle, in_vec, 1, NULL, 0, false); +} + +psa_status_t psa_aead_update_ad(psa_aead_operation_t *operation, + const uint8_t *input, + size_t input_length) +{ + if (operation->handle <= PSA_NULL_HANDLE) { + return PSA_ERROR_BAD_STATE; + } + + psa_crypto_ipc_aead_t psa_crypto_ipc = { + .func = PSA_AEAD_UPDATE_AD, + .handle = 0, + .alg = 0, + }; + + psa_invec in_vec[2] = { + { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }, + { input, input_length }, + }; + + return ipc_call(&operation->handle, in_vec, 2, NULL, 0, false); +} + +psa_status_t psa_aead_update(psa_aead_operation_t *operation, + const uint8_t *input, + size_t input_length, + uint8_t *output, + size_t output_size, + size_t *output_length) +{ + if (operation->handle <= PSA_NULL_HANDLE) { + return PSA_ERROR_BAD_STATE; + } + + psa_crypto_ipc_aead_t psa_crypto_ipc = { + .func = PSA_AEAD_UPDATE, + .handle = 0, + .alg = 0, + }; + + psa_invec in_vec[2] = { + { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }, + { input, input_length }, + }; + + psa_outvec out_vec[2] = { + { output, output_size }, + { output_length, sizeof(*output_length) }, + }; + + return ipc_call(&operation->handle, in_vec, 2, out_vec, 2, false); +} + +psa_status_t psa_aead_finish(psa_aead_operation_t *operation, + uint8_t *ciphertext, + size_t ciphertext_size, + size_t *ciphertext_length, + uint8_t *tag, + size_t tag_size, + size_t *tag_length) +{ + if (operation->handle <= PSA_NULL_HANDLE) { + return PSA_ERROR_BAD_STATE; + } + + psa_crypto_ipc_t psa_crypto_ipc = { + .func = PSA_AEAD_FINISH, + .handle = 0, + .alg = 0 + }; + + psa_invec in_vec[1] = { + { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }, + }; + + psa_outvec out_vec[4] = { + { ciphertext, ciphertext_size }, + { ciphertext_length, (ciphertext_length == NULL ? 0 : sizeof(*ciphertext_length)) }, + { tag, tag_size }, + { tag_length, (tag_length == NULL ? 0 : sizeof(*tag_length)) }, + }; + + return ipc_call(&operation->handle, in_vec, 1, out_vec, 4, true); +} + +psa_status_t psa_aead_verify(psa_aead_operation_t *operation, + uint8_t *plaintext, + size_t plaintext_size, + size_t *plaintext_length, + const uint8_t *tag, + size_t tag_length) +{ + if (operation->handle <= PSA_NULL_HANDLE) { + return PSA_ERROR_BAD_STATE; + } + + psa_crypto_ipc_t psa_crypto_ipc = { + .func = PSA_AEAD_VERIFY, + .handle = 0, + .alg = 0 + }; + + psa_invec in_vec[3] = { + { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }, + { tag, tag_length }, + }; + + psa_outvec out_vec[2] = { + { plaintext, plaintext_size }, + { plaintext_length, (plaintext_length == NULL ? 0 : sizeof(*plaintext_length)) }, + }; + + return ipc_call(&operation->handle, in_vec, 3, out_vec, 2, true); +} + +psa_status_t psa_aead_abort(psa_aead_operation_t *operation) +{ + if (operation->handle <= PSA_NULL_HANDLE) { + return PSA_SUCCESS; + } + + psa_crypto_ipc_aead_t psa_crypto_ipc = { + .func = PSA_AEAD_ABORT, + .handle = 0, + .alg = 0 + }; + + psa_invec in_vec = { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }; + + return ipc_call(&operation->handle, &in_vec, 1, NULL, 0, true); +} + +psa_status_t psa_sign_hash(psa_key_handle_t handle, + psa_algorithm_t alg, + const uint8_t *hash, + size_t hash_length, + uint8_t *signature, + size_t signature_size, + size_t *signature_length) +{ + psa_crypto_ipc_asymmetric_t psa_crypto_ipc = { + .func = PSA_SIGN_HASH, + .handle = handle, + .alg = alg, + .input_length = 0, + .salt_length = 0 + }; + + psa_invec in_vec[2] = { + { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }, + { hash, hash_length } + }; + + psa_outvec out_vec[2] = { + { signature, signature_size }, + { signature_length, sizeof(*signature_length) } + }; + + psa_status_t status = ipc_oneshot(PSA_ASYMMETRIC_ID, in_vec, 2, out_vec, 2); + return (status); +} + +psa_status_t psa_verify_hash(psa_key_handle_t handle, + psa_algorithm_t alg, + const uint8_t *hash, + size_t hash_length, + const uint8_t *signature, + size_t signature_size) +{ + psa_crypto_ipc_asymmetric_t psa_crypto_ipc = { + .func = PSA_VERIFY_HASH, + .handle = handle, + .alg = alg, + .input_length = 0, + .salt_length = 0 + }; + + psa_invec in_vec[3] = { + { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }, + { signature, signature_size }, + { hash, hash_length } + }; + + psa_status_t status = ipc_oneshot(PSA_ASYMMETRIC_ID, in_vec, 3, NULL, 0); + return (status); +} + +static psa_status_t psa_asymmetric_operation(psa_sec_function_t func, + psa_key_handle_t handle, + psa_algorithm_t alg, + const uint8_t *input, + size_t input_length, + const uint8_t *salt, + size_t salt_length, + uint8_t *output, + size_t output_size, + size_t *output_length) +{ + uint8_t *buffer = calloc(1, (input_length + salt_length)); + if (buffer == NULL) { + return (PSA_ERROR_INSUFFICIENT_MEMORY); + } + + psa_crypto_ipc_asymmetric_t psa_crypto_ipc = { + .func = func, + .handle = handle, + .alg = alg, + .input_length = input_length, + .salt_length = salt_length + }; + + psa_invec in_vec[2] = { + { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }, + { buffer, (input_length + salt_length) } + }; + + psa_outvec out_vec[2] = { + { output, output_size }, + { output_length, sizeof(*output_length) } + }; + + psa_status_t status; + memcpy(buffer, input, input_length); + memcpy(buffer + input_length, salt, salt_length); + + status = ipc_oneshot(PSA_ASYMMETRIC_ID, in_vec, 2, out_vec, 2); + free(buffer); + return (status); +} + +psa_status_t psa_asymmetric_encrypt(psa_key_handle_t handle, + psa_algorithm_t alg, + const uint8_t *input, + size_t input_length, + const uint8_t *salt, + size_t salt_length, + uint8_t *output, + size_t output_size, + size_t *output_length) +{ + psa_status_t status = psa_asymmetric_operation(PSA_ASYMMETRIC_ENCRYPT, + handle, + alg, input, input_length, + salt, salt_length, output, + output_size, output_length); + return (status); +} + +psa_status_t psa_asymmetric_decrypt(psa_key_handle_t handle, + psa_algorithm_t alg, + const uint8_t *input, + size_t input_length, + const uint8_t *salt, + size_t salt_length, + uint8_t *output, + size_t output_size, + size_t *output_length) +{ + psa_status_t status = psa_asymmetric_operation(PSA_ASYMMETRIC_DECRYPT, + handle, + alg, input, input_length, + salt, salt_length, output, + output_size, output_length); + return (status); +} + +psa_status_t psa_key_derivation_setup( + psa_key_derivation_operation_t *operation, + psa_algorithm_t alg) +{ + if (operation->handle != PSA_NULL_HANDLE) { + return PSA_ERROR_BAD_STATE; + } + + psa_crypto_derivation_ipc_t psa_crypto_ipc = { + .func = PSA_KEY_DERIVATION_SETUP, + .handle = 0, + .alg = alg + }; + + psa_invec in_vec = { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }; + + psa_status_t status = ipc_connect(PSA_KEY_DERIVATION_ID, &operation->handle); + if (status != PSA_SUCCESS) { + return status; + } + + status = ipc_call(&operation->handle, &in_vec, 1, NULL, 0, false); + if (status != PSA_SUCCESS) { + ipc_close(&operation->handle); + } + + return status; +} + +psa_status_t psa_key_derivation_get_capacity( + const psa_key_derivation_operation_t *op, + size_t *capacity) +{ + psa_key_derivation_operation_t *operation = (psa_key_derivation_operation_t *) op; + + if (operation->handle <= PSA_NULL_HANDLE) { + return PSA_ERROR_BAD_STATE; + } + + psa_crypto_derivation_ipc_t psa_crypto_ipc = { + .func = PSA_KEY_DERIVATION_GET_CAPACITY, + .handle = 0, + .alg = 0, + }; + + psa_invec in_vec = { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }; + + psa_outvec out_vec = { capacity, sizeof(*capacity) }; + + return ipc_call(&operation->handle, &in_vec, 1, &out_vec, 1, false); +} + +psa_status_t psa_key_derivation_set_capacity( + psa_key_derivation_operation_t *operation, + size_t capacity) +{ + if (operation->handle <= PSA_NULL_HANDLE) { + return PSA_ERROR_BAD_STATE; + } + + psa_crypto_derivation_ipc_t psa_crypto_ipc = { + .func = PSA_KEY_DERIVATION_SET_CAPACITY, + .handle = 0, + .alg = 0, + }; + + psa_invec in_vec[2] = { + { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }, + { &capacity, sizeof(capacity) }, + }; + + return ipc_call(&operation->handle, in_vec, 2, NULL, 0, false); +} + +psa_status_t psa_key_derivation_input_bytes( + psa_key_derivation_operation_t *operation, + psa_key_derivation_step_t step, + const uint8_t *data, + size_t data_length) +{ + if (operation->handle <= PSA_NULL_HANDLE) { + return PSA_ERROR_BAD_STATE; + } + + psa_crypto_derivation_ipc_t psa_crypto_ipc = { + .func = PSA_KEY_DERIVATION_INPUT_BYTES, + .handle = 0, + .alg = 0, + }; + + psa_invec in_vec[3] = { + { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }, + { &step, sizeof(step) }, + { data, data_length }, + }; + + return ipc_call(&operation->handle, in_vec, 3, NULL, 0, false); +} + +psa_status_t psa_key_derivation_input_key( + psa_key_derivation_operation_t *operation, + psa_key_derivation_step_t step, + psa_key_handle_t handle) +{ + if (operation->handle <= PSA_NULL_HANDLE) { + return PSA_ERROR_BAD_STATE; + } + + psa_crypto_derivation_ipc_t psa_crypto_ipc = { + .func = PSA_KEY_DERIVATION_INPUT_KEY, + .handle = handle, + .alg = 0 + }; + + psa_invec in_vec[2] = { + { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }, + { &step, sizeof(step) }, + }; + + psa_status_t status = ipc_call(&operation->handle, in_vec, 2, NULL, 0, false); + return (status); +} + +psa_status_t psa_key_derivation_key_agreement( + psa_key_derivation_operation_t *operation, + psa_key_derivation_step_t step, + psa_key_handle_t private_key, + const uint8_t *peer_key, + size_t peer_key_length) +{ + if (operation->handle <= PSA_NULL_HANDLE) { + return PSA_ERROR_BAD_STATE; + } + + psa_crypto_derivation_ipc_t psa_crypto_ipc = { + .func = PSA_KEY_DERIVATION_KEY_AGREEMENT, + .handle = private_key, + .alg = 0, + }; + + psa_invec in_vec[3] = { + { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }, + { &step, sizeof(step) }, + { peer_key, peer_key_length }, + }; + + return ipc_call(&operation->handle, in_vec, 3, NULL, 0, false); +} + +psa_status_t psa_key_derivation_output_bytes( + psa_key_derivation_operation_t *operation, + uint8_t *output, + size_t output_length) +{ + if (operation->handle <= PSA_NULL_HANDLE) { + return PSA_ERROR_BAD_STATE; + } + + psa_crypto_derivation_ipc_t psa_crypto_ipc = { + .func = PSA_KEY_DERIVATION_OUTPUT_BYTES, + .handle = 0, + }; + + psa_invec in_vec = { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }; + + psa_outvec out_vec = { output, output_length }; + + return ipc_call(&operation->handle, &in_vec, 1, &out_vec, 1, false); +} + +psa_status_t psa_key_derivation_output_key( + const psa_key_attributes_t *attributes, + psa_key_derivation_operation_t *operation, + psa_key_handle_t *handle) +{ + if (operation->handle <= PSA_NULL_HANDLE) { + return PSA_ERROR_BAD_STATE; + } + + psa_crypto_derivation_ipc_t psa_crypto_ipc = { + .func = PSA_KEY_DERIVATION_OUTPUT_KEY, + }; + + psa_invec in_vec[2] = { + { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }, + { attributes, sizeof(*attributes) }, + }; + + psa_outvec out_vec = { handle, sizeof(*handle) }; + + return ipc_call(&operation->handle, in_vec, 2, &out_vec, 1, false); +} + +psa_status_t psa_key_derivation_abort( + psa_key_derivation_operation_t *operation) +{ + if (operation->handle <= PSA_NULL_HANDLE) { + return PSA_SUCCESS; + } + + psa_crypto_derivation_ipc_t psa_crypto_ipc = { + .func = PSA_KEY_DERIVATION_ABORT, + .handle = 0, + .alg = 0, + }; + + psa_invec in_vec = { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }; + + return ipc_call(&operation->handle, &in_vec, 1, NULL, 0, true); +} + +psa_status_t psa_raw_key_agreement(psa_algorithm_t alg, + psa_key_handle_t private_key, + const uint8_t *peer_key, + size_t peer_key_length, + uint8_t *output, + size_t output_size, + size_t *output_length) +{ + psa_crypto_derivation_ipc_t psa_crypto_ipc = { + .func = PSA_RAW_KEY_AGREEMENT, + .handle = private_key, + .alg = alg, + }; + + psa_invec in_vec[2] = { + { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }, + { peer_key, peer_key_length }, + }; + + psa_outvec out_vec[2] = { + { output, output_size }, + { output_length, sizeof(*output_length) } + }; + + return ipc_oneshot(PSA_KEY_DERIVATION_ID, in_vec, 2, out_vec, 2); +} + +psa_status_t psa_generate_random(uint8_t *output, + size_t output_size) +{ + psa_outvec out_vec = { output, output_size }; + + psa_status_t status = ipc_oneshot(PSA_RNG_ID, NULL, 0, &out_vec, 1); + return (status); +} + +psa_status_t psa_generate_key(const psa_key_attributes_t *attributes, + psa_key_handle_t *handle) +{ + psa_key_mng_ipc_t psa_key_mng_ipc = { + .func = PSA_GENERATE_KEY, + }; + + psa_invec in_vec[2] = { + { &psa_key_mng_ipc, sizeof(psa_key_mng_ipc) }, + { attributes, sizeof(*attributes) }, + }; + + psa_outvec out_vec = { handle, sizeof(*handle) }; + + return ipc_oneshot(PSA_KEY_MNG_ID, in_vec, 2, &out_vec, 1); +} + + +/* + * PSA Crypto API extensions (crypto_extra.h) + */ + +void mbedtls_psa_crypto_free(void) +{ + ipc_oneshot(PSA_CRYPTO_FREE_ID, NULL, 0, NULL, 0); +} + +psa_status_t mbedtls_psa_inject_entropy(const uint8_t *seed, + size_t seed_size) +{ + psa_invec in_vec = { seed, seed_size }; + + psa_status_t status = ipc_oneshot(PSA_ENTROPY_ID, &in_vec, 1, NULL, 0); + return (status); +} + +#endif /* MBEDTLS_PSA_CRYPTO_C */ diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/inc/autogen_sid.h b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/inc/autogen_sid.h new file mode 100644 index 0000000..d344068 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/inc/autogen_sid.h @@ -0,0 +1,111 @@ +/* Copyright (c) 2019 ARM Limited + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/******************************************************************************* + * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + * THIS FILE IS AN AUTO-GENERATED FILE - DO NOT MODIFY IT. + * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + * Template Version 1.0 + * Generated by tools/psa/generate_partition_code.py Version 1.1 + ******************************************************************************/ + +/****************** Service Partitions ****************************************/ + +/* ----------------------------------------------------------------------------- + * ATTEST_SRV Service IDs + * -------------------------------------------------------------------------- */ + +#define PSA_ATTEST_GET_TOKEN_ID 0x00000F10 +#define PSA_ATTEST_GET_TOKEN_SIZE_ID 0x00000F11 +#define PSA_ATTEST_INJECT_KEY_ID 0x00000F12 + +/* ----------------------------------------------------------------------------- + * CRYPTO_SRV Service IDs + * -------------------------------------------------------------------------- */ + +#define PSA_CRYPTO_INIT_ID 0x00000F00 +#define PSA_MAC_ID 0x00000F01 +#define PSA_HASH_ID 0x00000F02 +#define PSA_ASYMMETRIC_ID 0x00000F03 +#define PSA_SYMMETRIC_ID 0x00000F04 +#define PSA_AEAD_ID 0x00000F05 +#define PSA_KEY_MNG_ID 0x00000F06 +#define PSA_RNG_ID 0x00000F07 +#define PSA_CRYPTO_FREE_ID 0x00000F08 +#define PSA_KEY_DERIVATION_ID 0x00000F09 +#define PSA_ENTROPY_ID 0x00000F0A + +/* ----------------------------------------------------------------------------- + * PLATFORM Service IDs + * -------------------------------------------------------------------------- */ + +#define PSA_PLATFORM_LC_GET 0x00011000 +#define PSA_PLATFORM_LC_SET 0x00011001 +#define PSA_PLATFORM_SYSTEM_RESET 0x00011002 +#define PSA_PLATFORM_IOCTL 0x00011003 + +/* ----------------------------------------------------------------------------- + * ITS Service IDs + * -------------------------------------------------------------------------- */ + +#define PSA_ITS_GET 0x00011A00 +#define PSA_ITS_SET 0x00011A01 +#define PSA_ITS_INFO 0x00011A02 +#define PSA_ITS_REMOVE 0x00011A03 +#define PSA_ITS_RESET 0x00011A04 + +/****************** Test Partitions *******************************************/ + +/* ----------------------------------------------------------------------------- + * CRYPTO_ACL_TEST Service IDs + * -------------------------------------------------------------------------- */ + +#define CRYPTO_GENERATE_KEY 0x00000201 +#define CRYPTO_OPEN_KEY 0x00000202 +#define CRYPTO_CLOSE_KEY 0x00000203 +#define CRYPTO_DESTROY_KEY 0x00000205 +#define CRYPTO_GET_KEY_ATTRIBUTES 0x00000206 +#define CRYPTO_IMPORT_KEY 0x00000208 + +/* ----------------------------------------------------------------------------- + * CLIENT_TESTS_PART1 Service IDs + * -------------------------------------------------------------------------- */ + +#define CLIENT_TESTS_PART1_ROT_SRV1 0x00001A05 +#define CLIENT_TESTS_PART1_DROP_CONN 0x00001A06 +#define CLIENT_TESTS_PART1_SECURE_CLIENTS_ONLY 0x00001A07 + +/* ----------------------------------------------------------------------------- + * SERVER_TESTS_PART1 Service IDs + * -------------------------------------------------------------------------- */ + +#define SERVER_TESTS_PART1_CONTROL 0x00001A01 +#define SERVER_TESTS_PART1_TEST 0x00001A02 + +/* ----------------------------------------------------------------------------- + * SERVER_TESTS_PART2 Service IDs + * -------------------------------------------------------------------------- */ + +#define SERVER_TESTS_PART2_ROT_SRV_REVERSE 0x00001A03 +#define SERVER_TESTS_PART2_ROT_SRV_DB_TST 0x00001A04 + +/* ----------------------------------------------------------------------------- + * SMOKE_TESTS_PART1 Service IDs + * -------------------------------------------------------------------------- */ + +#define SMOKE_TESTS_PART1_ROT_SRV1 0x00001A00 + diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/inc/mbed_spm_partitions.h b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/inc/mbed_spm_partitions.h new file mode 100644 index 0000000..acf4122 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/inc/mbed_spm_partitions.h @@ -0,0 +1,310 @@ +/* Copyright (c) 2017-2019 ARM Limited + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/******************************************************************************* + * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + * THIS FILE IS AN AUTO-GENERATED FILE - DO NOT MODIFY IT. + * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + * Template Version 1.0 + * Generated by tools/psa/generate_partition_code.py Version 1.1 + ******************************************************************************/ + +#ifndef __MBED_SPM_PARTITIONS_H___ +#define __MBED_SPM_PARTITIONS_H___ + + +/****************** Common definitions ****************************************/ + +/* PSA reserved event flags */ +#define PSA_RESERVED1_POS (1UL) +#define PSA_RESERVED1_MSK (1UL << PSA_RESERVED1_POS) + +#define PSA_RESERVED2_POS (2UL) +#define PSA_RESERVED2_MSK (1UL << PSA_RESERVED2_POS) + +/****************** Service Partitions ****************************************/ + +/* ----------------------------------------------------------------------------- + * ATTEST_SRV defines + * -------------------------------------------------------------------------- */ +#define ATTEST_SRV_ID 37 + +#define ATTEST_SRV_ROT_SRV_COUNT (3UL) +#define ATTEST_SRV_EXT_ROT_SRV_COUNT (7UL) + + +#define ATTEST_SRV_WAIT_ANY_IRQ_MSK (0) + +#define PSA_ATTEST_GET_TOKEN_POS (4UL) +#define PSA_ATTEST_GET_TOKEN (1UL << PSA_ATTEST_GET_TOKEN_POS) +#define PSA_ATTEST_GET_TOKEN_SIZE_POS (5UL) +#define PSA_ATTEST_GET_TOKEN_SIZE (1UL << PSA_ATTEST_GET_TOKEN_SIZE_POS) +#define PSA_ATTEST_INJECT_KEY_POS (6UL) +#define PSA_ATTEST_INJECT_KEY (1UL << PSA_ATTEST_INJECT_KEY_POS) + +#define ATTEST_SRV_WAIT_ANY_SID_MSK (\ + PSA_ATTEST_GET_TOKEN | \ + PSA_ATTEST_GET_TOKEN_SIZE | \ + PSA_ATTEST_INJECT_KEY) + + +/* ----------------------------------------------------------------------------- + * CRYPTO_SRV defines + * -------------------------------------------------------------------------- */ +#define CRYPTO_SRV_ID 35 + +#define CRYPTO_SRV_ROT_SRV_COUNT (11UL) +#define CRYPTO_SRV_EXT_ROT_SRV_COUNT (4UL) + + +#define CRYPTO_SRV_WAIT_ANY_IRQ_MSK (0) + +#define PSA_CRYPTO_INIT_POS (4UL) +#define PSA_CRYPTO_INIT (1UL << PSA_CRYPTO_INIT_POS) +#define PSA_MAC_POS (5UL) +#define PSA_MAC (1UL << PSA_MAC_POS) +#define PSA_HASH_POS (6UL) +#define PSA_HASH (1UL << PSA_HASH_POS) +#define PSA_ASYMMETRIC_POS (7UL) +#define PSA_ASYMMETRIC (1UL << PSA_ASYMMETRIC_POS) +#define PSA_SYMMETRIC_POS (8UL) +#define PSA_SYMMETRIC (1UL << PSA_SYMMETRIC_POS) +#define PSA_AEAD_POS (9UL) +#define PSA_AEAD (1UL << PSA_AEAD_POS) +#define PSA_KEY_MNG_POS (10UL) +#define PSA_KEY_MNG (1UL << PSA_KEY_MNG_POS) +#define PSA_RNG_POS (11UL) +#define PSA_RNG (1UL << PSA_RNG_POS) +#define PSA_CRYPTO_FREE_POS (12UL) +#define PSA_CRYPTO_FREE (1UL << PSA_CRYPTO_FREE_POS) +#define PSA_KEY_DERIVATION_POS (13UL) +#define PSA_KEY_DERIVATION (1UL << PSA_KEY_DERIVATION_POS) +#define PSA_ENTROPY_INJECT_POS (14UL) +#define PSA_ENTROPY_INJECT (1UL << PSA_ENTROPY_INJECT_POS) + +#define CRYPTO_SRV_WAIT_ANY_SID_MSK (\ + PSA_CRYPTO_INIT | \ + PSA_MAC | \ + PSA_HASH | \ + PSA_ASYMMETRIC | \ + PSA_SYMMETRIC | \ + PSA_AEAD | \ + PSA_KEY_MNG | \ + PSA_RNG | \ + PSA_CRYPTO_FREE | \ + PSA_KEY_DERIVATION | \ + PSA_ENTROPY_INJECT) + + +/* ----------------------------------------------------------------------------- + * PLATFORM defines + * -------------------------------------------------------------------------- */ +#define PLATFORM_ID 8 + +#define PLATFORM_ROT_SRV_COUNT (4UL) +#define PLATFORM_EXT_ROT_SRV_COUNT (1UL) + + +#define PLATFORM_WAIT_ANY_IRQ_MSK (0) + +#define PSA_PLATFORM_LC_GET_MSK_POS (4UL) +#define PSA_PLATFORM_LC_GET_MSK (1UL << PSA_PLATFORM_LC_GET_MSK_POS) +#define PSA_PLATFORM_LC_SET_MSK_POS (5UL) +#define PSA_PLATFORM_LC_SET_MSK (1UL << PSA_PLATFORM_LC_SET_MSK_POS) +#define PSA_PLATFORM_SYSTEM_RESET_MSK_POS (6UL) +#define PSA_PLATFORM_SYSTEM_RESET_MSK (1UL << PSA_PLATFORM_SYSTEM_RESET_MSK_POS) +#define PSA_PLATFORM_IOCTL_MSK_POS (7UL) +#define PSA_PLATFORM_IOCTL_MSK (1UL << PSA_PLATFORM_IOCTL_MSK_POS) + +#define PLATFORM_WAIT_ANY_SID_MSK (\ + PSA_PLATFORM_LC_GET_MSK | \ + PSA_PLATFORM_LC_SET_MSK | \ + PSA_PLATFORM_SYSTEM_RESET_MSK | \ + PSA_PLATFORM_IOCTL_MSK) + + +/* ----------------------------------------------------------------------------- + * ITS defines + * -------------------------------------------------------------------------- */ +#define ITS_ID 10 + +#define ITS_ROT_SRV_COUNT (5UL) +#define ITS_EXT_ROT_SRV_COUNT (0UL) + + +#define ITS_WAIT_ANY_IRQ_MSK (0) + +#define PSA_ITS_GET_MSK_POS (4UL) +#define PSA_ITS_GET_MSK (1UL << PSA_ITS_GET_MSK_POS) +#define PSA_ITS_SET_MSK_POS (5UL) +#define PSA_ITS_SET_MSK (1UL << PSA_ITS_SET_MSK_POS) +#define PSA_ITS_INFO_MSK_POS (6UL) +#define PSA_ITS_INFO_MSK (1UL << PSA_ITS_INFO_MSK_POS) +#define PSA_ITS_REMOVE_MSK_POS (7UL) +#define PSA_ITS_REMOVE_MSK (1UL << PSA_ITS_REMOVE_MSK_POS) +#define PSA_ITS_RESET_MSK_POS (8UL) +#define PSA_ITS_RESET_MSK (1UL << PSA_ITS_RESET_MSK_POS) + +#define ITS_WAIT_ANY_SID_MSK (\ + PSA_ITS_GET_MSK | \ + PSA_ITS_SET_MSK | \ + PSA_ITS_INFO_MSK | \ + PSA_ITS_REMOVE_MSK | \ + PSA_ITS_RESET_MSK) + + + +/****************** Test Partitions *******************************************/ + +#ifdef USE_PSA_TEST_PARTITIONS + +#ifdef USE_CRYPTO_ACL_TEST +/* ----------------------------------------------------------------------------- + * CRYPTO_ACL_TEST defines + * -------------------------------------------------------------------------- */ +#define CRYPTO_ACL_TEST_ID 128 + +#define CRYPTO_ACL_TEST_ROT_SRV_COUNT (6UL) +#define CRYPTO_ACL_TEST_EXT_ROT_SRV_COUNT (1UL) + + +#define CRYPTO_ACL_TEST_WAIT_ANY_IRQ_MSK (0) + +#define CRYPTO_GENERATE_KEY_MSK_POS (4UL) +#define CRYPTO_GENERATE_KEY_MSK (1UL << CRYPTO_GENERATE_KEY_MSK_POS) +#define CRYPTO_OPEN_KEY_MSK_POS (5UL) +#define CRYPTO_OPEN_KEY_MSK (1UL << CRYPTO_OPEN_KEY_MSK_POS) +#define CRYPTO_CLOSE_KEY_MSK_POS (6UL) +#define CRYPTO_CLOSE_KEY_MSK (1UL << CRYPTO_CLOSE_KEY_MSK_POS) +#define CRYPTO_DESTROY_KEY_MSK_POS (7UL) +#define CRYPTO_DESTROY_KEY_MSK (1UL << CRYPTO_DESTROY_KEY_MSK_POS) +#define CRYPTO_GET_KEY_ATTRIBUTES_MSK_POS (8UL) +#define CRYPTO_GET_KEY_ATTRIBUTES_MSK (1UL << CRYPTO_GET_KEY_ATTRIBUTES_MSK_POS) +#define CRYPTO_IMPORT_KEY_MSK_POS (9UL) +#define CRYPTO_IMPORT_KEY_MSK (1UL << CRYPTO_IMPORT_KEY_MSK_POS) + +#define CRYPTO_ACL_TEST_WAIT_ANY_SID_MSK (\ + CRYPTO_GENERATE_KEY_MSK | \ + CRYPTO_OPEN_KEY_MSK | \ + CRYPTO_CLOSE_KEY_MSK | \ + CRYPTO_DESTROY_KEY_MSK | \ + CRYPTO_GET_KEY_ATTRIBUTES_MSK | \ + CRYPTO_IMPORT_KEY_MSK) + + +#endif // USE_CRYPTO_ACL_TEST + +#ifdef USE_CLIENT_TESTS_PART1 +/* ----------------------------------------------------------------------------- + * CLIENT_TESTS_PART1 defines + * -------------------------------------------------------------------------- */ +#define CLIENT_TESTS_PART1_ID 1 + +#define CLIENT_TESTS_PART1_ROT_SRV_COUNT (3UL) +#define CLIENT_TESTS_PART1_EXT_ROT_SRV_COUNT (0UL) + + +#define CLIENT_TESTS_PART1_WAIT_ANY_IRQ_MSK (0) + +#define PART1_ROT_SRV1_MSK_POS (4UL) +#define PART1_ROT_SRV1_MSK (1UL << PART1_ROT_SRV1_MSK_POS) +#define DROP_CONN_MSK_POS (5UL) +#define DROP_CONN_MSK (1UL << DROP_CONN_MSK_POS) +#define SECURE_CLIENTS_ONLY_MSK_POS (6UL) +#define SECURE_CLIENTS_ONLY_MSK (1UL << SECURE_CLIENTS_ONLY_MSK_POS) + +#define CLIENT_TESTS_PART1_WAIT_ANY_SID_MSK (\ + PART1_ROT_SRV1_MSK | \ + DROP_CONN_MSK | \ + SECURE_CLIENTS_ONLY_MSK) + + +#endif // USE_CLIENT_TESTS_PART1 + +#ifdef USE_SERVER_TESTS_PART1 +/* ----------------------------------------------------------------------------- + * SERVER_TESTS_PART1 defines + * -------------------------------------------------------------------------- */ +#define SERVER_TESTS_PART1_ID 2 + +#define SERVER_TESTS_PART1_ROT_SRV_COUNT (2UL) +#define SERVER_TESTS_PART1_EXT_ROT_SRV_COUNT (2UL) + + +#define SERVER_TESTS_PART1_WAIT_ANY_IRQ_MSK (0) + +#define CONTROL_MSK_POS (4UL) +#define CONTROL_MSK (1UL << CONTROL_MSK_POS) +#define TEST_MSK_POS (5UL) +#define TEST_MSK (1UL << TEST_MSK_POS) + +#define SERVER_TESTS_PART1_WAIT_ANY_SID_MSK (\ + CONTROL_MSK | \ + TEST_MSK) + + +#endif // USE_SERVER_TESTS_PART1 + +#ifdef USE_SERVER_TESTS_PART2 +/* ----------------------------------------------------------------------------- + * SERVER_TESTS_PART2 defines + * -------------------------------------------------------------------------- */ +#define SERVER_TESTS_PART2_ID 3 + +#define SERVER_TESTS_PART2_ROT_SRV_COUNT (2UL) +#define SERVER_TESTS_PART2_EXT_ROT_SRV_COUNT (0UL) + + +#define SERVER_TESTS_PART2_WAIT_ANY_IRQ_MSK (0) + +#define ROT_SRV_REVERSE_MSK_POS (4UL) +#define ROT_SRV_REVERSE_MSK (1UL << ROT_SRV_REVERSE_MSK_POS) +#define ROT_SRV_DB_TST_MSK_POS (5UL) +#define ROT_SRV_DB_TST_MSK (1UL << ROT_SRV_DB_TST_MSK_POS) + +#define SERVER_TESTS_PART2_WAIT_ANY_SID_MSK (\ + ROT_SRV_REVERSE_MSK | \ + ROT_SRV_DB_TST_MSK) + + +#endif // USE_SERVER_TESTS_PART2 + +#ifdef USE_SMOKE_TESTS_PART1 +/* ----------------------------------------------------------------------------- + * SMOKE_TESTS_PART1 defines + * -------------------------------------------------------------------------- */ +#define SMOKE_TESTS_PART1_ID 4 + +#define SMOKE_TESTS_PART1_ROT_SRV_COUNT (1UL) +#define SMOKE_TESTS_PART1_EXT_ROT_SRV_COUNT (0UL) + + +#define SMOKE_TESTS_PART1_WAIT_ANY_IRQ_MSK (0) + +#define ROT_SRV1_MSK_POS (4UL) +#define ROT_SRV1_MSK (1UL << ROT_SRV1_MSK_POS) + +#define SMOKE_TESTS_PART1_WAIT_ANY_SID_MSK (\ + ROT_SRV1_MSK) + + +#endif // USE_SMOKE_TESTS_PART1 + + +#endif // USE_PSA_TEST_PARTITIONS + +#endif // __MBED_SPM_PARTITIONS_H___ diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/platform/COMPONENT_PSA_SRV_EMUL/platform_emul.c b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/platform/COMPONENT_PSA_SRV_EMUL/platform_emul.c new file mode 100644 index 0000000..8523413 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/platform/COMPONENT_PSA_SRV_EMUL/platform_emul.c @@ -0,0 +1,40 @@ +/* Copyright (c) 2019 ARM Limited + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "psa/lifecycle.h" +#include "platform_srv_impl.h" + +uint32_t psa_security_lifecycle_state(void) +{ + uint32_t lc_state = 0; + psa_status_t status = PSA_SUCCESS; + status = psa_platfrom_lifecycle_get_impl(&lc_state); + if (status != PSA_SUCCESS) { + lc_state = PSA_LIFECYCLE_UNKNOWN; + } + return lc_state; +} + +psa_status_t mbed_psa_reboot_and_request_new_security_state(uint32_t new_state) +{ + return psa_platfrom_lifecycle_change_request_impl(new_state); +} + +void mbed_psa_system_reset(void) +{ + mbed_psa_system_reset_impl(); +} diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/platform/COMPONENT_PSA_SRV_IMPL/platform_srv_impl.c b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/platform/COMPONENT_PSA_SRV_IMPL/platform_srv_impl.c new file mode 100644 index 0000000..9854633 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/platform/COMPONENT_PSA_SRV_IMPL/platform_srv_impl.c @@ -0,0 +1,56 @@ +/* Copyright (c) 2019-2020 Arm Limited + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "psa/lifecycle.h" +#include "psa/internal_trusted_storage.h" +#include "platform_srv_impl.h" +#include "cmsis.h" + +#ifndef MBED_CONF_LIFECYCLE_STATE +#define MBED_CONF_LIFECYCLE_STATE PSA_LIFECYCLE_ASSEMBLY_AND_TEST +#endif + +psa_status_t psa_platfrom_lifecycle_get_impl(uint32_t *lc_state) +{ + *lc_state = MBED_CONF_LIFECYCLE_STATE; + return PSA_SUCCESS; +} + +psa_status_t psa_its_reset(); + +psa_status_t psa_platfrom_lifecycle_change_request_impl(uint32_t state) +{ + if (PSA_LIFECYCLE_ASSEMBLY_AND_TEST == state) { + return psa_its_reset(); + } + return PSA_ERROR_NOT_SUPPORTED; +} + +MBED_WEAK void mbed_psa_system_reset_impl(void) +{ + /* Reset the system */ + NVIC_SystemReset(); +} + +MBED_WEAK enum tfm_platform_err_t tfm_platform_hal_ioctl(tfm_platform_ioctl_req_t request, + psa_invec *in_vec, + psa_outvec *out_vec) +{ + (void)in_vec; + (void)out_vec; + return TFM_PLATFORM_ERR_NOT_SUPPORTED; +} diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/platform/COMPONENT_PSA_SRV_IMPL/platform_srv_impl.h b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/platform/COMPONENT_PSA_SRV_IMPL/platform_srv_impl.h new file mode 100644 index 0000000..29e704f --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/platform/COMPONENT_PSA_SRV_IMPL/platform_srv_impl.h @@ -0,0 +1,43 @@ +/* Copyright (c) 2019-2020 Arm Limited + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __PLATFROM_SRV_IMPL_H__ +#define __PLATFROM_SRV_IMPL_H__ + +#include "psa/client.h" +#include "psa/lifecycle.h" +#include "mbed_toolchain.h" +#include "tfm_platform_api.h" + +psa_status_t psa_platfrom_lifecycle_get_impl(uint32_t *lc_state); +psa_status_t psa_platfrom_lifecycle_change_request_impl(uint32_t lc_state); +MBED_NORETURN void mbed_psa_system_reset_impl(void); + +/*! + * \brief Performs a platform-specific service + * + * \param[in] request Request identifier (valid values vary + * based on the platform) + * \param[in] in_vec Input buffer to the requested service (or NULL) + * \param[out] out_vec Output buffer to the requested service (or NULL) + * + * \return Returns values as specified by the \ref tfm_platform_err_t + */ +enum tfm_platform_err_t tfm_platform_hal_ioctl(tfm_platform_ioctl_req_t request, + psa_invec *in_vec, + psa_outvec *out_vec); +#endif // __PLATFROM_SRV_IMPL_H__ diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/platform/COMPONENT_PSA_SRV_IPC/platform_ipc.c b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/platform/COMPONENT_PSA_SRV_IPC/platform_ipc.c new file mode 100644 index 0000000..92cf1cd --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/platform/COMPONENT_PSA_SRV_IPC/platform_ipc.c @@ -0,0 +1,118 @@ +/* Copyright (c) 2019-2020 Arm Limited + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "psa_manifest/sid.h" +#include "psa/lifecycle.h" +#include "psa/client.h" +#include "mbed_toolchain.h" +#include "mbed_error.h" +#include "tfm_platform_api.h" + +uint32_t psa_security_lifecycle_state(void) +{ + psa_handle_t conn = psa_connect(PSA_PLATFORM_LC_GET, 1); + if (conn <= PSA_NULL_HANDLE) { + return PSA_LIFECYCLE_UNKNOWN; + } + + uint32_t lc_state = 0; + psa_outvec resp[1] = { {&lc_state, sizeof(lc_state)} }; + + psa_status_t status = psa_call(conn, NULL, 0, resp, 1); + if (status == PSA_DROP_CONNECTION) { + lc_state = PSA_LIFECYCLE_UNKNOWN; + } + + psa_close(conn); + + return lc_state; +} + +psa_status_t mbed_psa_reboot_and_request_new_security_state(uint32_t new_state) +{ + psa_handle_t conn = psa_connect(PSA_PLATFORM_LC_SET, 1); + if (conn <= PSA_NULL_HANDLE) { + return (psa_status_t) conn; + } + + psa_invec msg[1] = { + { &new_state, sizeof(new_state) } + }; + + psa_status_t status = psa_call(conn, msg, 1, NULL, 0); + + psa_close(conn); + return status; +} + +void mbed_psa_system_reset(void) +{ + psa_handle_t conn = psa_connect(PSA_PLATFORM_SYSTEM_RESET, 1); + if (conn > PSA_NULL_HANDLE) { + psa_call(conn, NULL, 0, NULL, 0); + } + error("reset failed - cannot connect to service handle=%ld", conn); +} + +enum tfm_platform_err_t +tfm_platform_ioctl(tfm_platform_ioctl_req_t request, + psa_invec *input, psa_outvec *output) { + tfm_platform_ioctl_req_t req = request; + struct psa_invec in_vec[2] = { {0} }; + size_t inlen, outlen; + psa_status_t status = PSA_ERROR_CONNECTION_REFUSED; + psa_handle_t handle = PSA_NULL_HANDLE; + + in_vec[0].base = &req; + in_vec[0].len = sizeof(req); + if (input != NULL) + { + in_vec[1].base = input->base; + in_vec[1].len = input->len; + inlen = 2; + } else + { + inlen = 1; + } + + if (output != NULL) + { + outlen = 1; + } else + { + outlen = 0; + } + + handle = psa_connect(PSA_PLATFORM_IOCTL, 1); + if (handle <= 0) + { + return TFM_PLATFORM_ERR_SYSTEM_ERROR; + } + + status = psa_call(handle, + in_vec, inlen, + output, outlen); + psa_close(handle); + + if (status < PSA_SUCCESS) + { + return TFM_PLATFORM_ERR_SYSTEM_ERROR; + } else + { + return (enum tfm_platform_err_t) status; + } +} diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/storage/common/psa_storage_common_impl.cpp b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/storage/common/psa_storage_common_impl.cpp new file mode 100644 index 0000000..1f68596 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/storage/common/psa_storage_common_impl.cpp @@ -0,0 +1,287 @@ +/* Copyright (c) 2018 ARM Limited + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include "TDBStore.h" +#include "psa_storage_common_impl.h" +#include "mbed_error.h" +#include "mbed_assert.h" +#include "mbed_toolchain.h" + +using namespace mbed; + +#ifdef __cplusplus +extern "C" +{ +#endif + +// Maximum length of filename we use for kvstore API. +// pid: 6; delimiter: 1; uid: 11; str terminator: 1 +#define PSA_STORAGE_FILE_NAME_MAX 19 + +#define FLAGS_MSK PSA_STORAGE_FLAG_WRITE_ONCE + +#define STR_EXPAND(tok) #tok + +const uint8_t base64_coding_table[] = { + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', + 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', + 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', + 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', + 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', + 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', + 'w', 'x', 'y', 'z', '0', '1', '2', '3', + '4', '5', '6', '7', '8', '9', '+', '-' +}; + +void psa_storage_handle_version(KVStore *kvstore, const char *version_key, const psa_storage_version_t *curr_version, + migrate_func_t migrate_func) +{ + psa_storage_version_t read_version = {0, 0}; + size_t actual_size = 0; + bool write_version = false; + int status = kvstore->get(version_key, &read_version, sizeof(read_version), &actual_size, 0); + if (status == MBED_SUCCESS) { + if (actual_size != sizeof(read_version)) { + error("PSA storage version data is corrupt"); + } + } else if (status == MBED_ERROR_ITEM_NOT_FOUND) { + write_version = true; + } else { + error("Could not read PSA storage version data"); + } + + if ((read_version.major > curr_version->major) || + ((read_version.major == curr_version->major) && (read_version.minor > curr_version->minor))) { + error("Downgrading PSA storage version is not allowed"); + } + + if ((read_version.major < curr_version->major) || + ((read_version.major == curr_version->major) && (read_version.minor < curr_version->minor))) { + psa_status_t migration_status = migrate_func(kvstore, &read_version, curr_version); + if (migration_status != PSA_SUCCESS) { + error("PSA storage migration failed"); + } + + write_version = true; + } + + if (write_version) { + if (kvstore->set(version_key, curr_version, sizeof(psa_storage_version_t), 0) != MBED_SUCCESS) { + error("Could not write PSA storage version"); + } + } +} + +/* + * \brief Convert KVStore stauts codes to PSA internal storage status codes + * + * \param[in] status - KVStore status code + * \return PSA internal storage status code + */ +static psa_status_t convert_status(int status) +{ + switch (status) { + case MBED_SUCCESS: + return PSA_SUCCESS; + case MBED_ERROR_WRITE_PROTECTED: + return PSA_ERROR_NOT_PERMITTED; + case MBED_ERROR_MEDIA_FULL: + return PSA_ERROR_INSUFFICIENT_STORAGE; + case MBED_ERROR_ITEM_NOT_FOUND: + return PSA_ERROR_DOES_NOT_EXIST; + case MBED_ERROR_INVALID_DATA_DETECTED: + return PSA_ERROR_DATA_CORRUPT; + case MBED_ERROR_INVALID_ARGUMENT: + return PSA_ERROR_INVALID_ARGUMENT; + case MBED_ERROR_READ_FAILED: // fallthrough + case MBED_ERROR_WRITE_FAILED: + return PSA_ERROR_STORAGE_FAILURE; + case MBED_ERROR_AUTHENTICATION_FAILED: // fallthrough + case MBED_ERROR_RBP_AUTHENTICATION_FAILED: + return PSA_ERROR_INVALID_SIGNATURE; + default: + return PSA_ERROR_GENERIC_ERROR; + } +} + +/* + * \brief Logic shift right + * + * \note must operate on unsinged integers to prevent negative carry + * \param x[in] input number for shifting + * \param n[in] number of bits to shift right + * \return the result + */ +static MBED_FORCEINLINE uint32_t lsr32(uint32_t x, uint32_t n) +{ + return x >> n; +} + +/* + * \brief Logic shift right + * + * \note must operate on unsinged integers to prevent negative carry + * \param x[in] input number for shifting + * \param n[in] number of bits to shift right + * \return the result + */ +static MBED_FORCEINLINE uint64_t lsr64(uint64_t x, uint32_t n) +{ + return x >> n; +} + +/* + * \breif Generate KVStore file name + * + * Generate KVStore file name by Base64 encoding PID and UID with a delimiter. + * Delimiter is required for determining between PID and UID. + * + * \param[out] tdb_filename - pointer to a buffer for the file name + * \param[in] tdb_filename_size - output buffer size + * \param[in] uid - PSA internal storage unique ID + * \param[in] pid - owner PSA partition ID + */ +static void generate_fn(char *tdb_filename, uint32_t tdb_filename_size, psa_storage_uid_t uid, int32_t pid) +{ + MBED_ASSERT(tdb_filename != NULL); + MBED_ASSERT(tdb_filename_size == PSA_STORAGE_FILE_NAME_MAX); + + uint8_t filename_idx = 0; + uint32_t unsigned_pid = (uint32_t)pid; // binary only representation for bitwise operations + + // Iterate on PID; each time convert 6 bits of PID into a character; first iteration must be done + do { + tdb_filename[filename_idx++] = base64_coding_table[unsigned_pid & 0x3F]; + unsigned_pid = lsr32(unsigned_pid, 6); + } while (unsigned_pid != 0); + + // Write delimiter + tdb_filename[filename_idx++] = '#'; + + // Iterate on UID; each time convert 6 bits of UID into a character; first iteration must be done + do { + tdb_filename[filename_idx++] = base64_coding_table[uid & 0x3F]; + uid = lsr64(uid, 6); + } while (uid != 0); + + tdb_filename[filename_idx++] = '\0'; + MBED_ASSERT(filename_idx <= PSA_STORAGE_FILE_NAME_MAX); +} + +psa_status_t psa_storage_set_impl(KVStore *kvstore, int32_t pid, psa_storage_uid_t uid, + size_t data_length, const void *p_data, + uint32_t kv_create_flags) +{ + if (uid == 0) { + return PSA_ERROR_INVALID_ARGUMENT; + } + // Generate KVStore key + char kv_key[PSA_STORAGE_FILE_NAME_MAX] = {'\0'}; + generate_fn(kv_key, PSA_STORAGE_FILE_NAME_MAX, uid, pid); + + int status = kvstore->set(kv_key, p_data, data_length, kv_create_flags); + + return convert_status(status); +} + +psa_status_t psa_storage_get_impl(KVStore *kvstore, int32_t pid, psa_storage_uid_t uid, + size_t data_offset, size_t data_length, void *p_data, size_t *p_data_length) +{ + if (uid == 0) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + // Generate KVStore key + char kv_key[PSA_STORAGE_FILE_NAME_MAX] = {'\0'}; + generate_fn(kv_key, PSA_STORAGE_FILE_NAME_MAX, uid, pid); + + KVStore::info_t kv_info; + int status = kvstore->get_info(kv_key, &kv_info); + + if (status == MBED_SUCCESS) { + if (data_offset > kv_info.size) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + // Verify (size + offset) does not wrap around + if (data_length + data_offset < data_length) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + if (data_offset + data_length > kv_info.size) { + return PSA_ERROR_BUFFER_TOO_SMALL; + } + + status = kvstore->get(kv_key, p_data, data_length, p_data_length, data_offset); + } + + return convert_status(status); +} + +psa_status_t psa_storage_get_info_impl(KVStore *kvstore, int32_t pid, psa_storage_uid_t uid, + struct psa_storage_info_t *p_info, uint32_t *kv_get_flags) +{ + + if (uid == 0) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + // Generate KVStore key + char kv_key[PSA_STORAGE_FILE_NAME_MAX] = {'\0'}; + generate_fn(kv_key, PSA_STORAGE_FILE_NAME_MAX, uid, pid); + + KVStore::info_t kv_info; + int status = kvstore->get_info(kv_key, &kv_info); + + if (status == MBED_SUCCESS) { + p_info->flags = 0; + if (kv_info.flags & KVStore::WRITE_ONCE_FLAG) { + p_info->flags |= PSA_STORAGE_FLAG_WRITE_ONCE; + } + *kv_get_flags = kv_info.flags; + p_info->size = kv_info.size; + p_info->capacity = kv_info.size; + } + + return convert_status(status); +} + +psa_status_t psa_storage_remove_impl(KVStore *kvstore, int32_t pid, psa_storage_uid_t uid) +{ + if (uid == 0) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + // Generate KVStore key + char kv_key[PSA_STORAGE_FILE_NAME_MAX] = {'\0'}; + generate_fn(kv_key, PSA_STORAGE_FILE_NAME_MAX, uid, pid); + + int status = kvstore->remove(kv_key); + + return convert_status(status); +} + +psa_status_t psa_storage_reset_impl(KVStore *kvstore) +{ + int status = kvstore->reset(); + return convert_status(status); +} + +#ifdef __cplusplus +} +#endif diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/storage/common/psa_storage_common_impl.h b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/storage/common/psa_storage_common_impl.h new file mode 100644 index 0000000..86f3617 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/storage/common/psa_storage_common_impl.h @@ -0,0 +1,50 @@ +/* Copyright (c) 2019 ARM Limited + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __PSA_STORAGE_COMMON_IMPL_H__ +#define __PSA_STORAGE_COMMON_IMPL_H__ + +#include "psa/error.h" +#include "psa/storage_common.h" +#include "KVStore.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +typedef struct { + uint32_t major; + uint32_t minor; +} psa_storage_version_t; + +typedef psa_status_t (*migrate_func_t)(mbed::KVStore *kvstore, const psa_storage_version_t *old_version, const psa_storage_version_t *new_version); + +void psa_storage_handle_version(mbed::KVStore *kvstore, const char *version_key, const psa_storage_version_t *version, + migrate_func_t migrate_func); +psa_status_t psa_storage_set_impl(mbed::KVStore *kvstore, int32_t pid, psa_storage_uid_t uid, size_t data_length, const void *p_data, uint32_t kv_create_flags); +psa_status_t psa_storage_get_impl(mbed::KVStore *kvstore, int32_t pid, psa_storage_uid_t uid, size_t data_offset, size_t data_length, void *p_data, size_t *p_data_length); +psa_status_t psa_storage_get_info_impl(mbed::KVStore *kvstore, int32_t pid, psa_storage_uid_t uid, struct psa_storage_info_t *p_info, uint32_t *kv_get_flags); +psa_status_t psa_storage_remove_impl(mbed::KVStore *kvstore, int32_t pid, psa_storage_uid_t uid); +psa_status_t psa_storage_reset_impl(mbed::KVStore *kvstore); + +#ifdef __cplusplus +} +#endif + + +#endif // __PSA_STORAGE_COMMON_IMPL_H__ diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/storage/its/COMPONENT_PSA_SRV_EMUL/psa_prot_internal_storage.cpp b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/storage/its/COMPONENT_PSA_SRV_EMUL/psa_prot_internal_storage.cpp new file mode 100644 index 0000000..bce3709 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/storage/its/COMPONENT_PSA_SRV_EMUL/psa_prot_internal_storage.cpp @@ -0,0 +1,108 @@ +/* Copyright (c) 2018 ARM Limited + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include "psa/internal_trusted_storage.h" +#include "psa/storage_common.h" +#include "pits_impl.h" +#include "kv_config.h" +#include "mbed_error.h" + +// In EMUL world, there is no real partitioning, which makes the source partition irrelevant. +// So here we set a global pid value to be used for when calling IMPL functions +#define PSA_ITS_EMUL_PID 1 + +psa_status_t psa_its_set(psa_storage_uid_t uid, size_t data_length, const void *p_data, psa_storage_create_flags_t create_flags) +{ + if (!p_data && data_length) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + // KVStore initiation: + // - In EMUL (non-secure single core) we do it here since we don't have another context to do it inside. + // - Repeating calls has no effect + int kv_status = kv_init_storage_config(); + if (kv_status != MBED_SUCCESS) { + return PSA_ERROR_STORAGE_FAILURE; + } + + psa_status_t res = psa_its_set_impl(PSA_ITS_EMUL_PID, uid, data_length, p_data, create_flags); + + return res; +} + +psa_status_t psa_its_get(psa_storage_uid_t uid, size_t data_offset, size_t data_length, void *p_data, size_t *p_data_length) +{ + if ((!p_data && data_length) || !p_data_length) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + // KVStore initiation: + // - In EMUL (non-secure single core) we do it here since we don't have another context to do it inside. + // - Repeating calls has no effect + int kv_status = kv_init_storage_config(); + if (kv_status != MBED_SUCCESS) { + return PSA_ERROR_STORAGE_FAILURE; + } + + return psa_its_get_impl(PSA_ITS_EMUL_PID, uid, data_offset, data_length, p_data, p_data_length); +} + +psa_status_t psa_its_get_info(psa_storage_uid_t uid, struct psa_storage_info_t *p_info) +{ + if (!p_info) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + // KVStore initiation: + // - In EMUL (non-secure single core) we do it here since we don't have another context to do it inside. + // - Repeating calls has no effect + int kv_status = kv_init_storage_config(); + if (kv_status != MBED_SUCCESS) { + return PSA_ERROR_STORAGE_FAILURE; + } + + return psa_its_get_info_impl(PSA_ITS_EMUL_PID, uid, p_info); +} + +psa_status_t psa_its_remove(psa_storage_uid_t uid) +{ + // KVStore initiation: + // - In EMUL (non-secure single core) we do it here since we don't have another context to do it inside. + // - Repeating calls has no effect + int kv_status = kv_init_storage_config(); + if (kv_status != MBED_SUCCESS) { + return PSA_ERROR_STORAGE_FAILURE; + } + + return psa_its_remove_impl(PSA_ITS_EMUL_PID, uid); +} + +extern "C" psa_status_t psa_its_reset() +{ + // KVStore initiation: + // - In EMUL (non-secure single core) we do it here since we don't have another context to do it inside. + // - Repeating calls has no effect + int kv_status = kv_init_storage_config(); + if (kv_status != MBED_SUCCESS) { + return PSA_ERROR_STORAGE_FAILURE; + } + + return psa_its_reset_impl(); +} diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/storage/its/COMPONENT_PSA_SRV_IMPL/TARGET_TFM/its_tfm_impl.cpp b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/storage/its/COMPONENT_PSA_SRV_IMPL/TARGET_TFM/its_tfm_impl.cpp new file mode 100644 index 0000000..46cd1a7 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/storage/its/COMPONENT_PSA_SRV_IMPL/TARGET_TFM/its_tfm_impl.cpp @@ -0,0 +1,157 @@ +/* Copyright (c) 2018 ARM Limited + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include "KVStore.h" +#include "TDBStore.h" +#include "psa/internal_trusted_storage.h" +#include "pits_impl.h" +#include "mbed_error.h" +#include "mbed_toolchain.h" +#include "FlashIAP.h" +#include "FlashIAPBlockDevice.h" + +using namespace mbed; + +static KVStore *internal_store = NULL; +static bool is_tfm_kv_initialized = false; + +static inline uint32_t align_up(uint64_t val, uint64_t size) +{ + return (((val - 1) / size) + 1) * size; +} + +static inline uint32_t align_down(uint64_t val, uint64_t size) +{ + return (((val) / size)) * size; +} + +static BlockDevice *_get_blockdevice(bd_addr_t start_address, bd_size_t size) +{ + int ret = MBED_SUCCESS; + bd_addr_t flash_end_address; + bd_addr_t flash_start_address; + bd_addr_t aligned_start_address; + bd_addr_t aligned_end_address; + bd_addr_t end_address; + FlashIAP flash; + + ret = flash.init(); + if (ret != 0) { + return NULL; + } + + //Get flash parameters before starting + flash_start_address = flash.get_flash_start(); + flash_end_address = flash_start_address + flash.get_flash_size();; + + aligned_start_address = align_down(start_address, flash.get_sector_size(start_address)); + if (start_address != aligned_start_address) { + flash.deinit(); + return NULL; + } + + end_address = start_address + size; + if (end_address > flash_end_address) { + flash.deinit(); + return NULL; + } + + aligned_end_address = align_up(end_address, flash.get_sector_size(end_address - 1)); + if (end_address != aligned_end_address) { + flash.deinit(); + return NULL; + } + + static FlashIAPBlockDevice bd(start_address, size); + flash.deinit(); + return &bd; +} + +static int _calculate_blocksize_match_tdbstore(BlockDevice *bd) +{ + bd_size_t size = bd->size(); + bd_size_t erase_size = bd->get_erase_size(); + bd_size_t number_of_sector = size / erase_size; + + if (number_of_sector < 2) { + return -1; + } + + return 0; +} + +static int tfm_kv_init(void) +{ + int ret = MBED_SUCCESS; + bd_size_t internal_size = MBED_CONF_STORAGE_TDB_INTERNAL_INTERNAL_SIZE; + bd_addr_t internal_start_address = MBED_CONF_STORAGE_TDB_INTERNAL_INTERNAL_BASE_ADDRESS; + + //Get internal memory FLASHIAP block device. + BlockDevice *internal_bd = _get_blockdevice(internal_start_address, internal_size); + if (internal_bd == NULL) { + return -1; // TODO: Error code + } + + ret = internal_bd->init(); + if (ret != 0) { + return ret; + } + + //Check that internal flash has 2 or more sectors + if (_calculate_blocksize_match_tdbstore(internal_bd) != 0) { + return -1; // TODO: Error code + } + + //Deinitialize internal block device and TDB will reinitialize and take control on it. + ret = internal_bd->deinit(); + if (ret != 0) { + return ret; + } + + //Create a TDBStore in the internal FLASHIAP block device. + static TDBStore tdb_internal(internal_bd); + internal_store = &tdb_internal; + + ret = internal_store->init(); + + return ret; +} + +/* + * \brief Get default KVStore instance for internal flesh storage + * + * \return valid pointer to KVStore + */ + +KVStore *get_its_kvstore_instance(void) +{ + return internal_store; +} +extern "C" int kv_init_storage_config() +{ + int ret = MBED_SUCCESS; + + if (!is_tfm_kv_initialized) { + ret = tfm_kv_init(); + } + + is_tfm_kv_initialized = (ret == MBED_SUCCESS) ? true : false; + return ret; +} + + diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/storage/its/COMPONENT_PSA_SRV_IMPL/pits_impl.cpp b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/storage/its/COMPONENT_PSA_SRV_IMPL/pits_impl.cpp new file mode 100644 index 0000000..6f0835d --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/storage/its/COMPONENT_PSA_SRV_IMPL/pits_impl.cpp @@ -0,0 +1,147 @@ +/* Copyright (c) 2019 ARM Limited + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include "KVStore.h" +#include "TDBStore.h" +#include "psa/internal_trusted_storage.h" +#include "psa_storage_common_impl.h" +#include "pits_impl.h" +#include "mbed_error.h" +#include "mbed_toolchain.h" + +using namespace mbed; + +#if defined(TARGET_TFM) +KVStore *get_its_kvstore_instance(void); +#else +#include "KVMap.h" +#endif + + + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define STR_EXPAND(tok) #tok +#define ITS_VERSION_KEY "PSA_ITS_VERSION" // ITS version entry identifier in TDBStore + +static KVStore *kvstore = NULL; +static bool initialized = false; + + +MBED_WEAK psa_status_t its_version_migrate(KVStore *kvstore, + const psa_storage_version_t *old_version, const psa_storage_version_t *new_version) +{ + (void)kvstore; + (void)old_version; + (void)new_version; + return PSA_SUCCESS; +} + + +static void its_init(void) +{ +#if defined(TARGET_TFM) + kvstore = get_its_kvstore_instance(); +#else + KVMap &kv_map = KVMap::get_instance(); + kvstore = kv_map.get_internal_kv_instance(STR_EXPAND(MBED_CONF_STORAGE_DEFAULT_KV)); +#endif + psa_storage_version_t version = {PSA_ITS_API_VERSION_MAJOR, PSA_ITS_API_VERSION_MINOR}; + if (!kvstore) { + // Can only happen due to system misconfiguration. + // Thus considered as unrecoverable error for runtime. + error("Failed getting kvstore instance\n"); + } + + psa_storage_handle_version(kvstore, ITS_VERSION_KEY, &version, its_version_migrate); + initialized = true; +} + +// used from test only +void its_deinit(void) +{ + kvstore = NULL; + initialized = false; +} + + +psa_status_t psa_its_set_impl(int32_t pid, psa_storage_uid_t uid, size_t data_length, const void *p_data, psa_storage_create_flags_t create_flags) +{ + if (!initialized) { + its_init(); + } + + if (create_flags & ~PSA_STORAGE_FLAG_WRITE_ONCE) { + return PSA_ERROR_NOT_SUPPORTED; + } + + return psa_storage_set_impl(kvstore, pid, uid, data_length, p_data, create_flags); +} + +psa_status_t psa_its_get_impl(int32_t pid, psa_storage_uid_t uid, size_t data_offset, size_t data_length, void *p_data, size_t *p_data_length) +{ + if (!initialized) { + its_init(); + } + + return psa_storage_get_impl(kvstore, pid, uid, data_offset, data_length, p_data, p_data_length); +} + +psa_status_t psa_its_get_info_impl(int32_t pid, psa_storage_uid_t uid, struct psa_storage_info_t *p_info) +{ + uint32_t kv_get_flags; + if (!initialized) { + its_init(); + } + + return psa_storage_get_info_impl(kvstore, pid, uid, p_info, &kv_get_flags); +} + +psa_status_t psa_its_remove_impl(int32_t pid, psa_storage_uid_t uid) +{ + if (!initialized) { + its_init(); + } + + return psa_storage_remove_impl(kvstore, pid, uid); +} + +psa_status_t psa_its_reset_impl() +{ + // Do not call its_init here to avoid version check before reset +#if defined(TARGET_TFM) + kvstore = get_its_kvstore_instance(); +#else + KVMap &kv_map = KVMap::get_instance(); + kvstore = kv_map.get_internal_kv_instance(STR_EXPAND(MBED_CONF_STORAGE_DEFAULT_KV)); +#endif + if (!kvstore) { + // Can only happen due to system misconfiguration. + // Thus considered as unrecoverable error for runtime. + error("Failed getting kvstore instance\n"); + } + + return psa_storage_reset_impl(kvstore); +} + +#ifdef __cplusplus +} +#endif diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/storage/its/COMPONENT_PSA_SRV_IMPL/pits_impl.h b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/storage/its/COMPONENT_PSA_SRV_IMPL/pits_impl.h new file mode 100644 index 0000000..43d076d --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/storage/its/COMPONENT_PSA_SRV_IMPL/pits_impl.h @@ -0,0 +1,39 @@ +/* Copyright (c) 2018 ARM Limited + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __PITS_IMPL_H__ +#define __PITS_IMPL_H__ + +#include "psa/error.h" +#include "psa/storage_common.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +psa_status_t psa_its_set_impl(int32_t pid, psa_storage_uid_t uid, size_t data_length, const void *p_data, psa_storage_create_flags_t create_flags); +psa_status_t psa_its_get_impl(int32_t pid, psa_storage_uid_t uid, size_t data_offset, size_t data_length, void *p_data, size_t *p_data_length); +psa_status_t psa_its_get_info_impl(int32_t pid, psa_storage_uid_t uid, struct psa_storage_info_t *p_info); +psa_status_t psa_its_remove_impl(int32_t pid, psa_storage_uid_t uid); +psa_status_t psa_its_reset_impl(); + +#ifdef __cplusplus +} +#endif + +#endif // __PITS_IMPL_H__ diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/storage/its/COMPONENT_PSA_SRV_IPC/psa_prot_internal_storage.c b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/storage/its/COMPONENT_PSA_SRV_IPC/psa_prot_internal_storage.c new file mode 100644 index 0000000..fb999af --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/storage/its/COMPONENT_PSA_SRV_IPC/psa_prot_internal_storage.c @@ -0,0 +1,137 @@ +/* Copyright (c) 2018 ARM Limited + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "psa/client.h" +#include "psa/storage_common.h" +#include "psa/internal_trusted_storage.h" +#include "psa_manifest/sid.h" + +psa_status_t psa_its_set(psa_storage_uid_t uid, size_t data_length, const void *p_data, psa_storage_create_flags_t create_flags) +{ + if (!p_data && data_length) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + psa_invec msg[3] = { + { &uid, sizeof(uid) }, + { p_data, data_length }, + { &create_flags, sizeof(create_flags) } + }; + + psa_handle_t conn = psa_connect(PSA_ITS_SET, 1); + if (conn <= PSA_NULL_HANDLE) { + return PSA_ERROR_STORAGE_FAILURE; + } + + psa_status_t status = psa_call(conn, msg, 3, NULL, 0); + if (status == PSA_DROP_CONNECTION) { + status = PSA_ERROR_STORAGE_FAILURE; + } + + psa_close(conn); + return status; +} + +psa_status_t psa_its_get(psa_storage_uid_t uid, size_t data_offset, size_t data_length, void *p_data, size_t *p_data_length) +{ + size_t actual_size = 0; + + if ((!p_data && data_length) || !p_data_length) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + psa_invec msg[2] = { + { &uid, sizeof(uid) }, + { &data_offset, sizeof(data_offset) } + }; + + psa_outvec resp[2] = { + { p_data, data_length }, + { &actual_size, sizeof(actual_size) } + }; + + psa_handle_t conn = psa_connect(PSA_ITS_GET, 1); + if (conn <= PSA_NULL_HANDLE) { + return PSA_ERROR_STORAGE_FAILURE; + } + + psa_status_t status = psa_call(conn, msg, 2, resp, 2); + + *p_data_length = actual_size; + + psa_close(conn); + return status; +} + +psa_status_t psa_its_get_info(psa_storage_uid_t uid, struct psa_storage_info_t *p_info) +{ + if (!p_info) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + struct psa_storage_info_t info = { 0, PSA_STORAGE_FLAG_NONE }; + psa_invec msg = { &uid, sizeof(uid) }; + psa_outvec resp = { &info, sizeof(info) }; + psa_handle_t conn = psa_connect(PSA_ITS_INFO, 1); + if (conn <= PSA_NULL_HANDLE) { + return PSA_ERROR_STORAGE_FAILURE; + } + + psa_status_t status = psa_call(conn, &msg, 1, &resp, 1); + + *p_info = info; + + if (status == PSA_DROP_CONNECTION) { + status = PSA_ERROR_STORAGE_FAILURE; + } + + psa_close(conn); + return status; +} + +psa_status_t psa_its_remove(psa_storage_uid_t uid) +{ + psa_invec msg = { &uid, sizeof(uid) }; + psa_handle_t conn = psa_connect(PSA_ITS_REMOVE, 1); + if (conn <= PSA_NULL_HANDLE) { + return PSA_ERROR_STORAGE_FAILURE; + } + + psa_status_t status = psa_call(conn, &msg, 1, NULL, 0); + if (status == PSA_DROP_CONNECTION) { + status = PSA_ERROR_STORAGE_FAILURE; + } + + psa_close(conn); + return status; +} + +psa_status_t psa_its_reset() +{ + psa_handle_t conn = psa_connect(PSA_ITS_RESET, 1); + if (conn <= PSA_NULL_HANDLE) { + return PSA_ERROR_STORAGE_FAILURE; + } + + psa_status_t status = psa_call(conn, NULL, 0, NULL, 0); + if (status == PSA_DROP_CONNECTION) { + status = PSA_ERROR_STORAGE_FAILURE; + } + + psa_close(conn); + return status; +} diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/storage/its/psa_prot_internal_storage.h b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/storage/its/psa_prot_internal_storage.h new file mode 100644 index 0000000..b4e1a0e --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/storage/its/psa_prot_internal_storage.h @@ -0,0 +1,164 @@ +/* Copyright (C) 2019, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** @file +@brief This file describes the PSA Internal Trusted Storage API +*/ + +#ifndef __PSA_INTERNAL_TRUSTED_STORAGE_H__ +#define __PSA_INTERNAL_TRUSTED_STORAGE_H__ + +#include +#include + +#include "psa/error.h" +#include "psa/storage_common.h" +#include "mbed_toolchain.h" + +#ifdef __cplusplus +extern "C" { +#endif +#define PSA_ITS_API_VERSION_MAJOR 1 /**< The major version number of the PSA ITS API. It will be incremented on significant updates that may include breaking changes */ +#define PSA_ITS_API_VERSION_MINOR 1 /**< The minor version number of the PSA ITS API. It will be incremented in small updates that are unlikely to include breaking changes */ + +// These deprecated types are still used by our PSA compliance test tools +MBED_DEPRECATED("ITS specific types should not be used") +typedef psa_status_t psa_its_status_t; + +MBED_DEPRECATED("ITS specific types should not be used") +typedef psa_storage_create_flags_t psa_its_create_flags_t; + +MBED_DEPRECATED("ITS specific types should not be used") +typedef psa_storage_uid_t psa_its_uid_t; + +MBED_DEPRECATED("ITS specific types should not be used") +#define psa_its_info_t psa_storage_info_t + +// These defines should also be deprecated +#define PSA_ITS_SUCCESS PSA_SUCCESS +#define PSA_ITS_ERROR_UID_NOT_FOUND PSA_ERROR_DOES_NOT_EXIST +#define PSA_ITS_ERROR_STORAGE_FAILURE PSA_ERROR_STORAGE_FAILURE +#define PSA_ITS_ERROR_INSUFFICIENT_SPACE PSA_ERROR_INSUFFICIENT_STORAGE +#define PSA_ITS_ERROR_OFFSET_INVALID PSA_ERROR_INVALID_ARGUMENT +#define PSA_ITS_ERROR_INCORRECT_SIZE PSA_ERROR_BUFFER_TOO_SMALL +#define PSA_ITS_ERROR_INVALID_ARGUMENTS PSA_ERROR_INVALID_ARGUMENT +#define PSA_ITS_ERROR_FLAGS_NOT_SUPPORTED PSA_ERROR_NOT_SUPPORTED +#define PSA_ITS_ERROR_WRITE_ONCE PSA_ERROR_NOT_PERMITTED +#define PSA_ITS_FLAG_WRITE_ONCE PSA_STORAGE_FLAG_WRITE_ONCE + +MBED_DEPRECATED("PS specific types should not be used") +typedef psa_status_t psa_ps_status_t; +MBED_DEPRECATED("PS specific types should not be used") +typedef psa_storage_uid_t psa_ps_uid_t; +MBED_DEPRECATED("PS specific types should not be used") +typedef psa_storage_create_flags_t psa_ps_create_flags_t; +MBED_DEPRECATED("PS specific types should not be used") +#define psa_ps_info_t psa_storage_info_t + +#define PSA_PS_SUCCESS PSA_SUCCESS +#define PSA_PS_ERROR_UID_NOT_FOUND PSA_ERROR_DOES_NOT_EXIST +#define PSA_PS_ERROR_STORAGE_FAILURE PSA_ERROR_STORAGE_FAILURE +#define PSA_PS_ERROR_INSUFFICIENT_SPACE PSA_ERROR_INSUFFICIENT_STORAGE +#define PSA_PS_ERROR_OFFSET_INVALID PSA_ERROR_INVALID_ARGUMENT +#define PSA_PS_ERROR_INCORRECT_SIZE PSA_ERROR_BUFFER_TOO_SMALL +#define PSA_PS_ERROR_INVALID_ARGUMENT PSA_ERROR_INVALID_ARGUMENT +#define PSA_PS_ERROR_FLAGS_NOT_SUPPORTED PSA_ERROR_NOT_SUPPORTED +#define PSA_PS_ERROR_WRITE_ONCE PSA_ERROR_NOT_PERMITTED +#define PSA_PS_FLAG_WRITE_ONCE PSA_STORAGE_FLAG_WRITE_ONCE + +/** + * \brief create a new or modify an existing uid/value pair + * + * \param[in] uid the identifier for the data + * \param[in] data_length The size in bytes of the data in `p_data` + * \param[in] p_data A buffer containing the data + * \param[in] create_flags The flags that the data will be stored with + * + * \return A status indicating the success/failure of the operation + + * \retval PSA_SUCCESS The operation completed successfully + * \retval PSA_ERROR_NOT_PERMITTED The operation failed because the provided `uid` value was already created with PSA_STORAGE_WRITE_ONCE_FLAG + * \retval PSA_ERROR_NOT_SUPPORTED The operation failed because one or more of the flags provided in `create_flags` is not supported or is not valid + * \retval PSA_ERROR_INSUFFICIENT_STORAGE The operation failed because there was insufficient space on the storage medium + * \retval PSA_ERROR_STORAGE_FAILURE The operation failed because the physical storage has failed (Fatal error) + * \retval PSA_ERROR_INVALID_ARGUMENTS The operation failed because one of the provided pointers(`p_data`) + * is invalid, for example is `NULL` or references memory the caller cannot access + */ +psa_status_t psa_its_set(psa_storage_uid_t uid, + size_t data_length, + const void *p_data, + psa_storage_create_flags_t create_flags); + +/** + * \brief Retrieve the value associated with a provided uid + * + * \param[in] uid The uid value + * \param[in] data_offset The starting offset of the data requested + * \param[in] data_length the amount of data requested (and the minimum allocated size of the `p_data` buffer) + * \param[out] p_data The buffer where the data will be placed upon successful completion + * \param[out] p_data_length The actual amount of data returned + + * + * \return A status indicating the success/failure of the operation + * + * \retval PSA_SUCCESS The operation completed successfully + * \retval PSA_ERROR_DOES_NOT_EXIST The operation failed because the provided `uid` value was not found in the storage + * \retval PSA_ERROR_BUFFER_TOO_SMALL The operation failed because the data associated with provided `uid` is not the same size as `data_size` + * \retval PSA_ERROR_STORAGE_FAILURE The operation failed because the physical storage has failed (Fatal error) + * \retval PSA_ERROR_INVALID_ARGUMENT The operation failed because one of the provided pointers(`p_data`, `p_data_length`) + * is invalid. For example is `NULL` or references memory the caller cannot access + */ +psa_status_t psa_its_get(psa_storage_uid_t uid, + size_t data_offset, + size_t data_length, + void *p_data, + size_t *p_data_length); + +/** + * \brief Retrieve the metadata about the provided uid + * + * \param[in] uid The uid value + * \param[out] p_info A pointer to the `psa_storage_info_t` struct that will be populated with the metadata + * + * \return A status indicating the success/failure of the operation + * + * \retval PSA_SUCCESS The operation completed successfully + * \retval PSA_ERROR_DOES_NOT_EXIST The operation failed because the provided uid value was not found in the storage + * \retval PSA_ERROR_STORAGE_FAILURE The operation failed because the physical storage has failed (Fatal error) + * \retval PSA_ERROR_INVALID_ARGUMENT The operation failed because one of the provided pointers(`p_info`) + * is invalid, for example is `NULL` or references memory the caller cannot access + */ +psa_status_t psa_its_get_info(psa_storage_uid_t uid, + struct psa_storage_info_t *p_info); + +/** + * \brief Remove the provided key and its associated data from the storage + * + * \param[in] uid The uid value + * + * \return A status indicating the success/failure of the operation + * + * \retval PSA_SUCCESS The operation completed successfully + * \retval PSA_ERROR_DOES_NOT_EXIST The operation failed because the provided key value was not found in the storage + * \retval PSA_ERROR_NOT_PERMITTED The operation failed because the provided key value was created with PSA_STORAGE_WRITE_ONCE_FLAG + * \retval PSA_ERROR_STORAGE_FAILURE The operation failed because the physical storage has failed (Fatal error) + */ +psa_status_t psa_its_remove(psa_storage_uid_t uid); + +#ifdef __cplusplus +} +#endif + +#endif // __PSA_INTERNAL_TRUSTED_STORAGE_H__ diff --git a/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/storage/ps/COMPONENT_NSPE/protected_storage.cpp b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/storage/ps/COMPONENT_NSPE/protected_storage.cpp new file mode 100644 index 0000000..65aea41 --- /dev/null +++ b/components/TARGET_PSA/TARGET_MBED_PSA_SRV/services/storage/ps/COMPONENT_NSPE/protected_storage.cpp @@ -0,0 +1,173 @@ +/* Copyright (c) 2019 ARM Limited + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include "KVMap.h" +#include "KVStore.h" +#include "kv_config.h" +#include "TDBStore.h" +#include "psa/protected_storage.h" +#include "psa_storage_common_impl.h" +#include "mbed_error.h" +#include "mbed_toolchain.h" + +using namespace mbed; + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define STR_EXPAND(tok) #tok +#define PS_VERSION_KEY "PSA_PS_VERSION" // PS version entry identifier in TDBStore + +// Global PID for protected storage, used when calling IMPL functions +#define PSA_PS_GLOBAL_PID 1 + +static KVStore *kvstore = NULL; +static bool initialized = false; + +MBED_WEAK psa_status_t ps_version_migrate(KVStore *kvstore, + const psa_storage_version_t *old_version, const psa_storage_version_t *new_version) +{ + (void)kvstore; + (void)old_version; + (void)new_version; + return PSA_SUCCESS; +} + + +static void ps_init(void) +{ + int ret = kv_init_storage_config(); + if (ret) { + // Can only happen due to system misconfiguration. + // Thus considered as unrecoverable error for runtime. + error("Failed initializing kvstore configuration\n"); + } + KVMap &kv_map = KVMap::get_instance(); + psa_storage_version_t version = {PSA_PS_API_VERSION_MAJOR, PSA_PS_API_VERSION_MINOR}; + kvstore = kv_map.get_main_kv_instance(STR_EXPAND(MBED_CONF_STORAGE_DEFAULT_KV)); + KVStore *int_kvstore = kv_map.get_internal_kv_instance(STR_EXPAND(MBED_CONF_STORAGE_DEFAULT_KV));; + if (!kvstore || !int_kvstore) { + // Can only happen due to system misconfiguration. + // Thus considered as unrecoverable error for runtime. + error("Failed getting kvstore instance\n"); + } + + psa_storage_handle_version(kvstore, PS_VERSION_KEY, &version, ps_version_migrate); + initialized = true; +} + +// used from test only +void ps_deinit(void) +{ + kvstore = NULL; + initialized = false; +} + + +psa_status_t psa_ps_set(psa_storage_uid_t uid, size_t data_length, const void *p_data, psa_storage_create_flags_t create_flags) +{ + if (!initialized) { + ps_init(); + } + + if (create_flags & ~ + (PSA_STORAGE_FLAG_WRITE_ONCE | PSA_STORAGE_FLAG_NO_CONFIDENTIALITY | PSA_STORAGE_FLAG_NO_REPLAY_PROTECTION)) { + return PSA_ERROR_NOT_SUPPORTED; + } + + // Assume confidentiality and replay protection are set by default + uint32_t kv_create_flags = KVStore::REQUIRE_CONFIDENTIALITY_FLAG | KVStore::REQUIRE_REPLAY_PROTECTION_FLAG; + + if (create_flags & PSA_STORAGE_FLAG_NO_CONFIDENTIALITY) { + kv_create_flags &= ~KVStore::REQUIRE_CONFIDENTIALITY_FLAG; + } + if (create_flags & PSA_STORAGE_FLAG_NO_REPLAY_PROTECTION) { + kv_create_flags &= ~KVStore::REQUIRE_REPLAY_PROTECTION_FLAG; + } + if (create_flags & PSA_STORAGE_FLAG_WRITE_ONCE) { + kv_create_flags |= KVStore::WRITE_ONCE_FLAG; + } + + return psa_storage_set_impl(kvstore, PSA_PS_GLOBAL_PID, uid, data_length, p_data, kv_create_flags); +} + +psa_status_t psa_ps_get(psa_storage_uid_t uid, size_t data_offset, size_t data_length, void *p_data, size_t *p_data_length) +{ + if (!initialized) { + ps_init(); + } + + return psa_storage_get_impl(kvstore, PSA_PS_GLOBAL_PID, uid, data_offset, data_length, p_data, p_data_length); +} + +psa_status_t psa_ps_get_info(psa_storage_uid_t uid, struct psa_storage_info_t *p_info) +{ + psa_status_t ret; + uint32_t kv_get_flags; + + if (!initialized) { + ps_init(); + } + + ret = psa_storage_get_info_impl(kvstore, PSA_PS_GLOBAL_PID, uid, p_info, &kv_get_flags); + + if ((kv_get_flags & ~KVStore::REQUIRE_CONFIDENTIALITY_FLAG) == kv_get_flags) { + p_info->flags |= PSA_STORAGE_FLAG_NO_CONFIDENTIALITY; + } + if ((kv_get_flags & ~KVStore::REQUIRE_REPLAY_PROTECTION_FLAG) == kv_get_flags) { + p_info->flags |= PSA_STORAGE_FLAG_NO_REPLAY_PROTECTION; + } + + return ret; +} + +psa_status_t psa_ps_remove(psa_storage_uid_t uid) +{ + if (!initialized) { + ps_init(); + } + + return psa_storage_remove_impl(kvstore, PSA_PS_GLOBAL_PID, uid); +} + +extern "C" psa_status_t psa_ps_reset() +{ + // Do not call its_init here to avoid version check before reset + int ret = kv_init_storage_config(); + if (ret) { + // Can only happen due to system misconfiguration. + // Thus considered as unrecoverable error for runtime. + error("Failed initializing kvstore configuration\n"); + } + + KVMap &kv_map = KVMap::get_instance(); + kvstore = kv_map.get_main_kv_instance(STR_EXPAND(MBED_CONF_STORAGE_DEFAULT_KV)); + if (!kvstore) { + // Can only happen due to system misconfiguration. + // Thus considered as unrecoverable error for runtime. + error("Failed getting kvstore instance\n"); + } + + return psa_storage_reset_impl(kvstore); +} + +#ifdef __cplusplus +} +#endif diff --git a/components/TARGET_PSA/TARGET_TFM/COMPONENT_NSPE/interface/src/tfm_ns_lock_rtx.c b/components/TARGET_PSA/TARGET_TFM/COMPONENT_NSPE/interface/src/tfm_ns_lock_rtx.c deleted file mode 100644 index d12d348..0000000 --- a/components/TARGET_PSA/TARGET_TFM/COMPONENT_NSPE/interface/src/tfm_ns_lock_rtx.c +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (c) 2017-2019, Arm Limited. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - * - */ -#include -#include -#include "cmsis.h" -#include "rtx_os.h" -#include "cmsis_os2.h" -#include "tfm_api.h" -#include "tfm_ns_lock.h" - -/** - * \brief struct ns_lock_state type - */ -struct ns_lock_state -{ - bool init; - osMutexId_t id; -}; - -/** - * \brief ns_lock status - */ -static struct ns_lock_state ns_lock = {.init=false, .id=NULL}; - -/** - * \brief Mutex properties, NS lock - */ - -static osRtxMutex_t ns_lock_cb = { 0 }; - -static const osMutexAttr_t ns_lock_attrib = { - .name = "ns_lock", - .attr_bits = osMutexPrioInherit, - .cb_mem = &ns_lock_cb, - .cb_size = sizeof(ns_lock_cb) -}; - -/** - * \brief NS world, NS lock based dispatcher - */ -__attribute__((weak)) -uint32_t tfm_ns_lock_dispatch(veneer_fn fn, - uint32_t arg0, uint32_t arg1, - uint32_t arg2, uint32_t arg3) -{ - uint32_t result; - - /* Check the NS lock has been initialized */ - if (ns_lock.init == false) { - return TFM_ERROR_GENERIC; - } - - /* TFM request protected by NS lock */ - if (osMutexAcquire(ns_lock.id,osWaitForever) != osOK) { - return TFM_ERROR_GENERIC; - } - - result = fn(arg0, arg1, arg2, arg3); - - if (osMutexRelease(ns_lock.id) != osOK) { - return TFM_ERROR_GENERIC; - } - - return result; -} - -/** - * \brief NS world, Init NS lock - */ -__attribute__((weak)) -enum tfm_status_e tfm_ns_lock_init() -{ - if (ns_lock.init == false) { - ns_lock.id = osMutexNew(&ns_lock_attrib); - ns_lock.init = true; - return TFM_SUCCESS; - } - else { - return TFM_ERROR_GENERIC; - } -} - -bool tfm_ns_lock_get_init_state() -{ - return ns_lock.init; -} - diff --git a/components/TARGET_PSA/TARGET_TFM/COMPONENT_NSPE/interface/src/tfm_psa_ns_api.c b/components/TARGET_PSA/TARGET_TFM/COMPONENT_NSPE/interface/src/tfm_psa_ns_api.c deleted file mode 100644 index 159eef9..0000000 --- a/components/TARGET_PSA/TARGET_TFM/COMPONENT_NSPE/interface/src/tfm_psa_ns_api.c +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (c) 2018, Arm Limited. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - * - */ - -#include "interface/include/psa_client.h" -#include "tfm_ns_lock.h" -#include "tfm_api.h" - -/**** API functions ****/ - -uint32_t psa_framework_version(void) -{ - return tfm_ns_lock_dispatch((veneer_fn)tfm_psa_framework_version_veneer, - 0, - 0, - 0, - 0); -} - -uint32_t psa_version(uint32_t sid) -{ - return tfm_ns_lock_dispatch((veneer_fn)tfm_psa_version_veneer, - sid, - 0, - 0, - 0); -} - -psa_handle_t psa_connect(uint32_t sid, uint32_t minor_version) -{ - return tfm_ns_lock_dispatch((veneer_fn)tfm_psa_connect_veneer, - sid, - minor_version, - 0, - 0); -} - -psa_status_t psa_call(psa_handle_t handle, - const psa_invec *in_vec, - size_t in_len, - psa_outvec *out_vec, - size_t out_len) -{ - /* FixMe: sanity check can be added to offload some NS thread checks from - * TFM secure API - */ - - /* Due to v8M restrictions, TF-M NS API needs to add another layer of - * serialization in order for NS to pass arguments to S - */ - psa_invec in_vecs, out_vecs; - - in_vecs.base = in_vec; - in_vecs.len = in_len; - out_vecs.base = out_vec; - out_vecs.len = out_len; - return tfm_ns_lock_dispatch((veneer_fn)tfm_psa_call_veneer, - (uint32_t)handle, - (uint32_t)&in_vecs, - (uint32_t)&out_vecs, - 0); -} - -void psa_close(psa_handle_t handle) -{ - tfm_ns_lock_dispatch((veneer_fn)tfm_psa_close_veneer, - (uint32_t)handle, - 0, - 0, - 0); -} - diff --git a/components/TARGET_PSA/TARGET_TFM/LICENSE b/components/TARGET_PSA/TARGET_TFM/LICENSE deleted file mode 100644 index 96810fd..0000000 --- a/components/TARGET_PSA/TARGET_TFM/LICENSE +++ /dev/null @@ -1,2 +0,0 @@ -Unless specifically indicated otherwise in a file, TF-M files in this directory are licensed under the BSD-3-Clause license, -as can be found in: LICENSE-bsd-3-clause.txt diff --git a/components/TARGET_PSA/TARGET_TFM/LICENSE-BSD-3-Clause b/components/TARGET_PSA/TARGET_TFM/LICENSE-BSD-3-Clause deleted file mode 100644 index 476769c..0000000 --- a/components/TARGET_PSA/TARGET_TFM/LICENSE-BSD-3-Clause +++ /dev/null @@ -1,26 +0,0 @@ -Copyright 2019 Arm Limited and affiliates. -SPDX-License-Identifier: BSD-3-Clause - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. -3. Neither the name of the copyright holder nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE -LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. diff --git a/components/TARGET_PSA/TARGET_TFM/interface/include/psa_client.h b/components/TARGET_PSA/TARGET_TFM/interface/include/psa_client.h deleted file mode 100644 index 71adb80..0000000 --- a/components/TARGET_PSA/TARGET_TFM/interface/include/psa_client.h +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright (c) 2018-2019, Arm Limited. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - * - */ - -#ifndef __PSA_CLIENT_H__ -#define __PSA_CLIENT_H__ - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include - -/*********************** PSA Client Macros and Types *************************/ - -#define PSA_FRAMEWORK_VERSION (0x0100) - -#define PSA_VERSION_NONE (0) - -/* PSA response types */ -#define PSA_SUCCESS (0) -#define PSA_CONNECTION_REFUSED (INT32_MIN + 1) -#define PSA_CONNECTION_BUSY (INT32_MIN + 2) -#define PSA_DROP_CONNECTION (INT32_MIN) - -/* PSA message handles */ -#define PSA_NULL_HANDLE ((psa_handle_t)0) - -typedef int32_t psa_status_t; -typedef int32_t psa_handle_t; - -/** - * A read-only input memory region provided to an RoT Service. - */ -typedef struct psa_invec { - const void *base; /*!< the start address of the memory buffer */ - size_t len; /*!< the size in bytes */ -} psa_invec; - -/** - * A writable output memory region provided to an RoT Service. - */ -typedef struct psa_outvec { - void *base; /*!< the start address of the memory buffer */ - size_t len; /*!< the size in bytes */ -} psa_outvec; - -/*************************** PSA Client API **********************************/ - -/** - * \brief Retrieve the version of the PSA Framework API that is implemented. - * - * \return version The version of the PSA Framework implementation - * that is providing the runtime services to the - * caller. The major and minor version are encoded - * as follows: - * \arg version[15:8] -- major version number. - * \arg version[7:0] -- minor version number. - */ -uint32_t psa_framework_version(void); - -/** - * \brief Retrieve the minor version of an RoT Service or indicate that it is - * not present on this system. - * - * \param[in] sid ID of the RoT Service to query. - * - * \retval PSA_VERSION_NONE The RoT Service is not implemented, or the - * caller is not permitted to access the service. - * \retval > 0 The minor version of the implemented RoT - * Service. - */ -uint32_t psa_version(uint32_t sid); - -/** - * \brief Connect to an RoT Service by its SID. - * - * \param[in] sid ID of the RoT Service to connect to. - * \param[in] minor_version Requested version of the RoT Service. - * - * \retval > 0 A handle for the connection. - * \retval PSA_CONNECTION_REFUSED The SPM or RoT Service has refused the - * connection. - * \retval PSA_CONNECTION_BUSY The SPM or RoT Service cannot make the - * connection at the moment. - * \retval "Does not return" The RoT Service ID and version are not - * supported, or the caller is not permitted to - * access the service. - */ -psa_handle_t psa_connect(uint32_t sid, uint32_t minor_version); - -/** - * \brief Call an RoT Service on an established connection. - * - * \param[in] handle A handle to an established connection. - * \param[in] in_vec Array of input \ref psa_invec structures. - * \param[in] in_len Number of input \ref psa_invec structures. - * \param[in/out] out_vec Array of output \ref psa_outvec structures. - * \param[in] out_len Number of output \ref psa_outvec structures. - * - * \retval >=0 RoT Service-specific status value. - * \retval <0 RoT Service-specific error code. - * \retval PSA_DROP_CONNECTION The connection has been dropped by the RoT - * Service. This indicates that either this or - * a previous message was invalid. - * \retval "Does not return" The call is invalid, one or more of the - * following are true: - * \arg An invalid handle was passed. - * \arg The connection is already handling a request. - * \arg An invalid memory reference was provided. - * \arg in_len + out_len > PSA_MAX_IOVEC. - * \arg The message is unrecognized by the RoT - * Service or incorrectly formatted. - */ -psa_status_t psa_call(psa_handle_t handle, - const psa_invec *in_vec, - size_t in_len, - psa_outvec *out_vec, - size_t out_len); - -/** - * \brief Close a connection to an RoT Service. - * - * \param[in] handle A handle to an established connection, or the - * null handle. - * - * \retval void Success. - * \retval "Does not return" The call is invalid, one or more of the - * following are true: - * \arg An invalid handle was provided that is not - * the null handle. - * \arg The connection is handling a request. - */ -void psa_close(psa_handle_t handle); - -#ifdef __cplusplus -} -#endif - -#endif /* __PSA_CLIENT_H__ */ diff --git a/components/TARGET_PSA/TARGET_TFM/interface/include/psa_service.h b/components/TARGET_PSA/TARGET_TFM/interface/include/psa_service.h deleted file mode 100644 index 6453aed..0000000 --- a/components/TARGET_PSA/TARGET_TFM/interface/include/psa_service.h +++ /dev/null @@ -1,250 +0,0 @@ -/* - * Copyright (c) 2018-2019, Arm Limited. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - * - */ - -#ifndef __PSA_SERVICE_H__ -#define __PSA_SERVICE_H__ - -#ifdef __cplusplus -extern "C" { -#endif - -#include - -/********************** PSA Secure Partition Macros and Types ****************/ - -/* PSA wait timeouts */ -#define PSA_POLL (0x00000000u) -#define PSA_BLOCK (0x80000000u) - -/* A mask value that includes all Secure Partition signals */ -#define PSA_WAIT_ANY (~0u) - -/* Doorbell signal */ -#define PSA_DOORBELL (0x00000008u) - -/* PSA message types */ -#define PSA_IPC_CONNECT (1) -#define PSA_IPC_CALL (2) -#define PSA_IPC_DISCONNECT (3) - -/* Maximum number of input and output vectors */ -#define PSA_MAX_IOVEC (4) - -/* Return code from psa_get() */ -#define PSA_ERR_NOMSG (INT32_MIN + 3) - -/* Store a set of one or more Secure Partition signals */ -typedef uint32_t psa_signal_t; - -/** - * Describe a message received by an RoT Service after calling \ref psa_get(). - */ -typedef struct psa_msg_t { - uint32_t type; /* One of the following values: - * \ref PSA_IPC_CONNECT - * \ref PSA_IPC_CALL - * \ref PSA_IPC_DISCONNECT - */ - psa_handle_t handle; /* A reference generated by the SPM to the - * message returned by psa_get(). - */ - int32_t client_id; /* Partition ID of the sender of the message */ - void *rhandle; /* Be useful for binding a connection to some - * application-specific data or function - * pointer within the RoT Service - * implementation. - */ - size_t in_size[PSA_MAX_IOVEC]; /* Provide the size of each client input - * vector in bytes. - */ - size_t out_size[PSA_MAX_IOVEC];/* Provide the size of each client output - * vector in bytes. - */ -} psa_msg_t; - -/************************* PSA Secure Partition API **************************/ - -/** - * \brief Return the Secure Partition interrupt signals that have been asserted - * from a subset of signals provided by the caller. - * - * \param[in] signal_mask A set of signals to query. Signals that are not - * in this set will be ignored. - * \param[in] timeout Specify either blocking \ref PSA_BLOCK or - * polling \ref PSA_POLL operation. - * - * \retval >0 At least one signal is asserted. - * \retval 0 No signals are asserted. This is only seen when - * a polling timeout is used. - */ -psa_signal_t psa_wait(psa_signal_t signal_mask, uint32_t timeout); - -/** - * \brief Retrieve the message which corresponds to a given RoT Service signal - * and remove the message from the RoT Service queue. - * - * \param[in] signal The signal value for an asserted RoT Service. - * \param[out] msg Pointer to \ref psa_msg_t object for receiving - * the message. - * - * \retval PSA_SUCCESS Success, *msg will contain the delivered - * message. - * \retval PSA_ERR_NOMSG Message could not be delivered. - * \retval "Does not return" The call is invalid because one or more of the - * following are true: - * \arg signal has more than a single bit set. - * \arg signal does not correspond to an RoT Service. - * \arg The RoT Service signal is not currently - * asserted. - * \arg The msg pointer provided is not a valid memory - * reference. - */ -psa_status_t psa_get(psa_signal_t signal, psa_msg_t *msg); - -/** - * \brief Associate some RoT Service private data with a client connection. - * - * \param[in] msg_handle Handle for the client's message. - * \param[in] rhandle Reverse handle allocated by the RoT Service. - * - * \retval void Success, rhandle will be provided with all - * subsequent messages delivered on this - * connection. - * \retval "Does not return" msg_handle is invalid. - */ -void psa_set_rhandle(psa_handle_t msg_handle, void *rhandle); - -/** - * \brief Read a message parameter or part of a message parameter from a client - * input vector. - * - * \param[in] msg_handle Handle for the client's message. - * \param[in] invec_idx Index of the input vector to read from. Must be - * less than \ref PSA_MAX_IOVEC. - * \param[out] buffer Buffer in the Secure Partition to copy the - * requested data to. - * \param[in] num_bytes Maximum number of bytes to be read from the - * client input vector. - * - * \retval >0 Number of bytes copied. - * \retval 0 There was no remaining data in this input - * vector. - * \retval "Does not return" The call is invalid, one or more of the - * following are true: - * \arg msg_handle is invalid. - * \arg msg_handle does not refer to a - * \ref PSA_IPC_CALL message. - * \arg invec_idx is equal to or greater than - * \ref PSA_MAX_IOVEC. - * \arg the memory reference for buffer is invalid or - * not writable. - */ -size_t psa_read(psa_handle_t msg_handle, uint32_t invec_idx, - void *buffer, size_t num_bytes); - -/** - * \brief Skip over part of a client input vector. - * - * \param[in] msg_handle Handle for the client's message. - * \param[in] invec_idx Index of input vector to skip from. Must be - * less than \ref PSA_MAX_IOVEC. - * \param[in] num_bytes Maximum number of bytes to skip in the client - * input vector. - * - * \retval >0 Number of bytes skipped. - * \retval 0 There was no remaining data in this input - * vector. - * \retval "Does not return" The call is invalid, one or more of the - * following are true: - * \arg msg_handle is invalid. - * \arg msg_handle does not refer to a - * \ref PSA_IPC_CALL message. - * \arg invec_idx is equal to or greater than - * \ref PSA_MAX_IOVEC. - */ -size_t psa_skip(psa_handle_t msg_handle, uint32_t invec_idx, size_t num_bytes); - -/** - * \brief Write a message response to a client output vector. - * - * \param[in] msg_handle Handle for the client's message. - * \param[out] outvec_idx Index of output vector in message to write to. - * Must be less than \ref PSA_MAX_IOVEC. - * \param[in] buffer Buffer with the data to write. - * \param[in] num_bytes Number of bytes to write to the client output - * vector. - * - * \retval void Success - * \retval "Does not return" The call is invalid, one or more of the - * following are true: - * \arg msg_handle is invalid. - * \arg msg_handle does not refer to a - * \ref PSA_IPC_CALL message. - * \arg outvec_idx is equal to or greater than - * \ref PSA_MAX_IOVEC. - * \arg The memory reference for buffer is invalid. - * \arg The call attempts to write data past the end - * of the client output vector. - */ -void psa_write(psa_handle_t msg_handle, uint32_t outvec_idx, - const void *buffer, size_t num_bytes); - -/** - * \brief Complete handling of a specific message and unblock the client. - * - * \param[in] msg_handle Handle for the client's message. - * \param[in] status Message result value to be reported to the - * client. - * - * \retval void Success. - * \retval "Does not return" The call is invalid, one or more of the - * following are true: - * \arg msg_handle is invalid. - * \arg An invalid status code is specified for the - * type of message. - */ -void psa_reply(psa_handle_t msg_handle, psa_status_t status); - -/** - * \brief Send a PSA_DOORBELL signal to a specific Secure Partition. - * - * \param[in] partition_id Secure Partition ID of the target partition. - * - * \retval void Success. - * \retval "Does not return" partition_id does not correspond to a Secure - * Partition. - */ -void psa_notify(int32_t partition_id); - -/** - * \brief Clear the PSA_DOORBELL signal. - * - * \retval void Success. - * \retval "Does not return" The Secure Partition's doorbell signal is not - * currently asserted. - */ -void psa_clear(void); - -/** - * \brief Inform the SPM that an interrupt has been handled (end of interrupt). - * - * \param[in] irq_signal The interrupt signal that has been processed. - * - * \retval void Success. - * \retval "Does not return" The call is invalid, one or more of the - * following are true: - * \arg irq_signal is not an interrupt signal. - * \arg irq_signal indicates more than one signal. - * \arg irq_signal is not currently asserted. - */ -void psa_eoi(psa_signal_t irq_signal); - -#ifdef __cplusplus -} -#endif - -#endif /* __PSA_SERVICE_H__ */ diff --git a/components/TARGET_PSA/TARGET_TFM/interface/include/tfm_api.h b/components/TARGET_PSA/TARGET_TFM/interface/include/tfm_api.h deleted file mode 100644 index d6ce689..0000000 --- a/components/TARGET_PSA/TARGET_TFM/interface/include/tfm_api.h +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright (c) 2017-2019, Arm Limited. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - * - */ - -#ifndef __TFM_API_H__ -#define __TFM_API_H__ - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include "psa_client.h" - -#define TFM_INVALID_CLIENT_ID 0 - -/** - * \brief Checks if the provided client ID is a secure client ID. - * - * \param[in] client_id Client ID to check - * - * \return Returns 1 if the client Id is secure. Otherwise, returns 0. - */ -#define TFM_CLIENT_ID_IS_S(client_id) ((client_id)>0) - -/** - * \brief Checks if the provided client ID is a non-secure client ID. - * - * \param[in] client_id Client ID to check - * - * \return Returns 1 if the client Id is non-secure. Otherwise, returns 0. - */ -#define TFM_CLIENT_ID_IS_NS(client_id) ((client_id)<0) - -/* Maximum number of input and output vectors */ -#define PSA_MAX_IOVEC (4) - -/* FixMe: sort out DEBUG compile option and limit return value options - * on external interfaces */ -/* For secure functions using prorietary signatures - * TFM will only return values recognized and parsed by TFM core. - * Service return codes are not automatically passed on to REE. - * Any non-zero return value is interpreted as an error that may trigger - * TEE error handling flow. - * For secure functions using the veneers in secure_fw/ns_callable/tfm_veneers.c - * (iovec API) this limitation does not apply. - */ -enum tfm_status_e -{ - TFM_SUCCESS = 0, - TFM_PARTITION_BUSY, - TFM_ERROR_SECURE_DOMAIN_LOCKED, - TFM_ERROR_INVALID_PARAMETER, - TFM_ERROR_PARTITION_NON_REENTRANT, - TFM_ERROR_NS_THREAD_MODE_CALL, - TFM_ERROR_NOT_INITIALIZED, - TFM_ERROR_NO_ACTIVE_PARTITION, - TFM_ERROR_INVALID_EXC_MODE, - TFM_SECURE_LOCK_FAILED, - TFM_SECURE_UNLOCK_FAILED, - TFM_ERROR_GENERIC = 0x1F, - TFM_PARTITION_SPECIFIC_ERROR_MIN, -}; - -//==================== Secure function declarations ==========================// - -/** - * \brief Assign client ID to the current TZ context - * - * \param[in] ns_client_id The client ID to be assigned to the current - * context - * \return TFM_SUCCESS if the client ID assigned successfully, an error code - * according to \ref tfm_status_e in case of error. - * - * \note This function have to be called from handler mode. - */ -enum tfm_status_e tfm_register_client_id (int32_t ns_client_id); - -/** - * \brief Retrieve the version of the PSA Framework API that is implemented - * - * \return The version of the PSA Framework - */ -uint32_t tfm_psa_framework_version_veneer(void); - -/** - * \brief Return version of secure function provided by secure binary - * - * \param[in] sid ID of secure service - * - * \return Version number of secure function - */ -uint32_t tfm_psa_version_veneer(uint32_t sid); - -/** - * \brief Connect to secure function - * - * \param[in] sid ID of secure service - * \param[in] minor_version Minor version of SF requested by client - * - * \return Returns handle to connection - */ -psa_handle_t tfm_psa_connect_veneer(uint32_t sid, uint32_t minor_version); - -/** - * \brief Call a secure function referenced by a connection handle - * - * \param[in] handle Handle to connection - * \param[in] in_vecs invec containing pointer/count of input vectors - * \param[in] out_vecs outvec containing pointer/count of output vectors - * - * \return Returns \ref psa_status_t status code - */ -psa_status_t tfm_psa_call_veneer(psa_handle_t handle, - const psa_invec *in_vecs, - psa_outvec *out_vecs); - -/** - * \brief Close connection to secure function referenced by a connection handle - * - * \param[in] handle Handle to connection - * - * \return Returns \ref psa_status_t status code - */ -psa_status_t tfm_psa_close_veneer(psa_handle_t handle); - -//================ End Secure function declarations ==========================// - -#ifdef __cplusplus -} -#endif - -#endif /* __TFM_API_H__ */ diff --git a/components/TARGET_PSA/TARGET_TFM/interface/include/tfm_ns_lock.h b/components/TARGET_PSA/TARGET_TFM/interface/include/tfm_ns_lock.h deleted file mode 100644 index d9acd00..0000000 --- a/components/TARGET_PSA/TARGET_TFM/interface/include/tfm_ns_lock.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2017-2019, Arm Limited. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - * - */ -#ifndef __TFM_NS_LOCK_H__ -#define __TFM_NS_LOCK_H__ - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include "tfm_api.h" - -typedef int32_t (*veneer_fn) (uint32_t arg0, uint32_t arg1, - uint32_t arg2, uint32_t arg3); - -/** - * \brief NS world, NS lock based dispatcher - * - * \details To be called from the wrapper API interface - */ - -uint32_t tfm_ns_lock_dispatch(veneer_fn fn, - uint32_t arg0, uint32_t arg1, - uint32_t arg2, uint32_t arg3); - -/** - * \brief NS world, Init NS lock - * - * \details Needs to be called during non-secure app init - * to initialize the TFM NS lock object - */ -enum tfm_status_e tfm_ns_lock_init(); - -#ifdef __cplusplus -} -#endif - -#endif /* __TFM_NS_LOCK_H__ */ diff --git a/components/TARGET_PSA/TARGET_TFM/interface/include/tfm_ns_svc.h b/components/TARGET_PSA/TARGET_TFM/interface/include/tfm_ns_svc.h deleted file mode 100644 index 366a70a..0000000 --- a/components/TARGET_PSA/TARGET_TFM/interface/include/tfm_ns_svc.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (c) 2017-2019, Arm Limited. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - * - */ - -#include -#include - -#ifndef __TFM_NS_SVC_H__ -#define __TFM_NS_SVC_H__ - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * \brief Include all the SVC handler headers - */ -#include "tfm_nspm_svc_handler.h" - -/** - * \brief Macro to encode an svc instruction - * - */ -#define SVC(code) __ASM volatile("svc %0" : : "I" (code)) - -/** - * \def LIST_SVC_NSPM - * - * \brief This is an X macro which lists - * the SVC interface exposed by TF-M - * for the NS OS. - * - */ -#define LIST_SVC_NSPM \ - X(SVC_TFM_NSPM_REGISTER_CLIENT_ID, tfm_nspm_svc_register_client_id) \ - -/** - * \brief Numbers associated to each SVC available - * - * \details Start from 1 as 0 is reserved by RTX - */ -enum tfm_svc_num { - SVC_INVALID = 0, - -#define X(SVC_ENUM, SVC_HANDLER) SVC_ENUM, - - /* SVC API for Services */ -#ifdef TFM_NS_CLIENT_IDENTIFICATION - LIST_SVC_NSPM -#endif - -#undef X - - /* add all the new entries above this line */ - SVC_TFM_MAX, -}; - -/* number of user SVC functions */ -#define USER_SVC_COUNT ((uint32_t)SVC_TFM_MAX - 1) - -#ifdef __cplusplus -} -#endif - -#endif /* __TFM_NS_SVC_H__ */ diff --git a/components/TARGET_PSA/TARGET_TFM/interface/include/tfm_nspm_svc_handler.h b/components/TARGET_PSA/TARGET_TFM/interface/include/tfm_nspm_svc_handler.h deleted file mode 100644 index 73f75a9..0000000 --- a/components/TARGET_PSA/TARGET_TFM/interface/include/tfm_nspm_svc_handler.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2018, Arm Limited. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - * - */ - -#ifndef __TFM_NSPM_SVC_HANDLER_H__ -#define __TFM_NSPM_SVC_HANDLER_H__ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * \brief Reports the client ID of this task to TF-M (SVC function) - * - * \param [in] client_id Client ID to register. - * - * \return Returns 1 if the client ID was successfully reported 0 otherwise - */ -uint32_t tfm_nspm_svc_register_client_id(uint32_t client_id); - -#ifdef __cplusplus -} -#endif - -#endif /* __TFM_NSPM_SVC_HANDLER_H__ */ diff --git a/components/TARGET_PSA/TARGET_TFM/mbed_lib.json b/components/TARGET_PSA/TARGET_TFM/mbed_lib.json deleted file mode 100644 index 0cf8e65..0000000 --- a/components/TARGET_PSA/TARGET_TFM/mbed_lib.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "name": "tfm", - "macros": [ - "TFM_PSA_API", "MBED_TZ_DEFAULT_ACCESS=1" - ], - "config": { - "level": { - "help": "TFM security level", - "macro_name": "TFM_LVL", - "value": 1 - }, - "handle_pool_size": { - "help": "maximum number of handles that can be opened at the same time", - "macro_name": "TFM_CONN_HANDLE_MAX_NUM", - "value": 10 - }, - "rot_pool_size": { - "help": "maximum number of RoT services allowed", - "macro_name": "TFM_SPM_MAX_ROT_SERV_NUM", - "value": 32 - }, - "message_pool_size": { - "help": "maximum number of active messages allowed", - "macro_name": "TFM_MSG_QUEUE_MAX_MSG_NUM", - "value": 10 - } - } -} - diff --git a/components/TARGET_PSA/TESTS/compliance_attestation/psa_attestation_testlist.md b/components/TARGET_PSA/TESTS/compliance_attestation/psa_attestation_testlist.md deleted file mode 100644 index d8d7f10..0000000 --- a/components/TARGET_PSA/TESTS/compliance_attestation/psa_attestation_testlist.md +++ /dev/null @@ -1,22 +0,0 @@ -# PSA Initial Attestation Testcase checklist - -| Test | Return value | API | Test Algorithm | Test Cases | -|-----------|--------------------------------------|-------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| test_a001 | PSA_ATTEST_ERR_SUCCESS | psa_initial_attest_get_token()
psa_initial_attest_get_token_size() | 1. Provide correct inputs to API with described challenge sizes
2. Expect API to return this define as return value each time
3. Verify the token | 1. Challenge_size = 32
2. Challenge_size = 48
3. Challenge_size = 64 | -| | PSA_ATTEST_ERR_INVALID_INPUT | psa_initial_attest_get_token()
psa_initial_attest_get_token_size() | 1. Provide described challenge sizes to the API along with other valid parameters
2. Expect API to return this define as return value each time | 1. Challenge_size is zero
2. Invalid challenge size between 0 and 32
3. Invalid challenge size between 32 and 64
4. Challenge_size is greater than MAX_CHALLENGE_SIZE | -| | PSA_ATTEST_ERR_TOKEN_BUFFER_OVERFLOW | psa_initial_attest_get_token() | 1. Provide described taken size to the API along with other valid parameters
2. Expect API to return this define as return value each time | Pass the token_size which less than actual/required token size | -| | PSA_ATTEST_ERR_INIT_FAILED | psa_initial_attest_get_token()
psa_initial_attest_get_token_size() | Can't simulate. Test can't generate stimulus where attestation initialisation fails | | -| | PSA_ATTEST_ERR_CLAIM_UNAVAILABLE | psa_initial_attest_get_token() | Can't simulate. Test can't generate stimulus where claim can unavailable | | -| | PSA_ATTEST_ERR_GENERAL | psa_initial_attest_get_token()
psa_initial_attest_get_token_size() | Can't simulate. Test can't generate stimulus where unexpected error happened during API operation | | - -## Note - -1. In verifying the token, only the data type of claims and presence of the mandatory claims are checked and the values of the claims are not checked. -2. Checks related to token signature validation will be part of future release - -# License -Arm PSA test suite is distributed under Apache v2.0 License. - --------------- - -*Copyright (c) 2019, Arm Limited and Contributors. All rights reserved.* diff --git a/components/TARGET_PSA/TESTS/compliance_attestation/test_a001/main.c b/components/TARGET_PSA/TESTS/compliance_attestation/test_a001/main.c deleted file mode 100644 index 2bdbffd..0000000 --- a/components/TARGET_PSA/TESTS/compliance_attestation/test_a001/main.c +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (c) 2020, Arm Limited and affiliates. - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include "val_interfaces.h" -#include "pal_mbed_os_intf.h" - -#if !defined(MBED_CONF_RTOS_PRESENT) -#error [NOT_SUPPORTED] PSA compliance attestation test cases require RTOS to run. -#else -void test_entry_a001(val_api_t *val_api, psa_api_t *psa_api); - -int main(void) -{ - test_start(test_entry_a001, COMPLIANCE_TEST_ATTESTATION); -} -#endif diff --git a/components/TARGET_PSA/TESTS/compliance_attestation/test_a001/test_a001.c b/components/TARGET_PSA/TESTS/compliance_attestation/test_a001/test_a001.c deleted file mode 100644 index edb8e59..0000000 --- a/components/TARGET_PSA/TESTS/compliance_attestation/test_a001/test_a001.c +++ /dev/null @@ -1,105 +0,0 @@ -/** @file - * Copyright (c) 2019, Arm Limited or its affiliates. All rights reserved. - * SPDX-License-Identifier : Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -**/ - -#include "val_interfaces.h" -#include "val_target.h" -#include "test_a001.h" -#include "test_data.h" - -client_test_t test_a001_attestation_list[] = { - NULL, - psa_initial_attestation_get_token_test, - psa_initial_attestation_get_token_size_test, - NULL, -}; - -static int g_test_count = 1; - -int32_t psa_initial_attestation_get_token_test(caller_security_t caller) -{ - int num_checks = sizeof(check1)/sizeof(check1[0]); - uint32_t i, status, token_size; - uint8_t challenge[PSA_INITIAL_ATTEST_CHALLENGE_SIZE_64+1]; - uint8_t token_buffer[TOKEN_SIZE]; - - for (i = 0; i < num_checks; i++) - { - val->print(PRINT_TEST, "[Check %d] ", g_test_count++); - val->print(PRINT_TEST, check1[i].test_desc, 0); - - memset(challenge, 0x2a, sizeof(challenge)); - memset(token_buffer, 0, sizeof(token_buffer)); - - status = val->attestation_function(VAL_INITIAL_ATTEST_GET_TOKEN_SIZE, - check1[i].challenge_size, &token_size); - if (status != PSA_SUCCESS) - { - if (check1[i].challenge_size != PSA_INITIAL_ATTEST_CHALLENGE_SIZE_32 || - check1[i].challenge_size != PSA_INITIAL_ATTEST_CHALLENGE_SIZE_48 || - check1[i].challenge_size != PSA_INITIAL_ATTEST_CHALLENGE_SIZE_64) - { - token_size = check1[i].token_size; - check1[i].challenge_size = check1[i].actual_challenge_size; - } - else - return status; - } - - status = val->attestation_function(VAL_INITIAL_ATTEST_GET_TOKEN, challenge, - check1[i].challenge_size, token_buffer, &token_size); - TEST_ASSERT_EQUAL(status, check1[i].expected_status, TEST_CHECKPOINT_NUM(1)); - - if (check1[i].expected_status != PSA_SUCCESS) - continue; - - /* Validate the token */ - status = val->attestation_function(VAL_INITIAL_ATTEST_VERIFY_TOKEN, challenge, - check1[i].challenge_size, token_buffer, token_size); - TEST_ASSERT_EQUAL(status, PSA_SUCCESS, TEST_CHECKPOINT_NUM(2)); - } - - return VAL_STATUS_SUCCESS; -} - -int32_t psa_initial_attestation_get_token_size_test(caller_security_t caller) -{ - int num_checks = sizeof(check2)/sizeof(check2[0]); - uint32_t i, status, token_size; - - for (i = 0; i < num_checks; i++) - { - val->print(PRINT_TEST, "[Check %d] ", g_test_count++); - val->print(PRINT_TEST, check2[i].test_desc, 0); - - status = val->attestation_function(VAL_INITIAL_ATTEST_GET_TOKEN_SIZE, - check2[i].challenge_size, &token_size); - - TEST_ASSERT_EQUAL(status, check2[i].expected_status, TEST_CHECKPOINT_NUM(1)); - - if (check2[i].expected_status != PSA_SUCCESS) - continue; - - if (token_size < check2[i].challenge_size) - { - val->print(PRINT_ERROR, "Token size less than challenge size\n", 0); - return VAL_STATUS_INSUFFICIENT_SIZE; - } - } - - return VAL_STATUS_SUCCESS; -} - diff --git a/components/TARGET_PSA/TESTS/compliance_attestation/test_a001/test_a001.h b/components/TARGET_PSA/TESTS/compliance_attestation/test_a001/test_a001.h deleted file mode 100644 index e066ee8..0000000 --- a/components/TARGET_PSA/TESTS/compliance_attestation/test_a001/test_a001.h +++ /dev/null @@ -1,33 +0,0 @@ -/** @file - * Copyright (c) 2019, Arm Limited or its affiliates. All rights reserved. - * SPDX-License-Identifier : Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -**/ -#ifndef _TEST_A001_CLIENT_TESTS_H_ -#define _TEST_A001_CLIENT_TESTS_H_ - -#include "val_attestation.h" -#define test_entry CONCAT(test_entry_, a001) -#define val CONCAT(val,test_entry) -#define psa CONCAT(psa,test_entry) - -#define TOKEN_SIZE 512 - -extern val_api_t *val; -extern psa_api_t *psa; -extern client_test_t test_a001_attestation_list[]; - -int32_t psa_initial_attestation_get_token_test(caller_security_t caller); -int32_t psa_initial_attestation_get_token_size_test(caller_security_t caller); -#endif /* _TEST_A001_CLIENT_TESTS_H_ */ diff --git a/components/TARGET_PSA/TESTS/compliance_attestation/test_a001/test_data.h b/components/TARGET_PSA/TESTS/compliance_attestation/test_a001/test_data.h deleted file mode 100644 index bfeba55..0000000 --- a/components/TARGET_PSA/TESTS/compliance_attestation/test_a001/test_data.h +++ /dev/null @@ -1,103 +0,0 @@ -/** @file - * Copyright (c) 2019, Arm Limited or its affiliates. All rights reserved. - * SPDX-License-Identifier : Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -**/ - -#include "val_attestation.h" - -typedef struct { - char test_desc[100]; - uint32_t challenge_size; - uint32_t actual_challenge_size; - uint32_t token_size; - psa_status_t expected_status; -} test_data; - - -static test_data check1[] = { -{"Test psa_initial_attestation_get_token with Challenge 32\n", - PSA_INITIAL_ATTEST_CHALLENGE_SIZE_32, PSA_INITIAL_ATTEST_CHALLENGE_SIZE_32, TOKEN_SIZE, PSA_SUCCESS -}, - -{"Test psa_initial_attestation_get_token with Challenge 48\n", - PSA_INITIAL_ATTEST_CHALLENGE_SIZE_48, PSA_INITIAL_ATTEST_CHALLENGE_SIZE_48, TOKEN_SIZE, PSA_SUCCESS -}, - -{"Test psa_initial_attestation_get_token with Challenge 64\n", - PSA_INITIAL_ATTEST_CHALLENGE_SIZE_64, PSA_INITIAL_ATTEST_CHALLENGE_SIZE_64, TOKEN_SIZE, PSA_SUCCESS -}, - -{"Test psa_initial_attestation_get_token with zero challenge size\n", - 0, 0, TOKEN_SIZE, PSA_ATTEST_ERR_INVALID_INPUT -}, - -{"Test psa_initial_attestation_get_token with small challenge size\n", - PSA_INITIAL_ATTEST_CHALLENGE_SIZE_32-1, PSA_INITIAL_ATTEST_CHALLENGE_SIZE_32-1, - TOKEN_SIZE, PSA_ATTEST_ERR_INVALID_INPUT -}, - -{"Test psa_initial_attestation_get_token with invalid challenge size\n", - PSA_INITIAL_ATTEST_CHALLENGE_SIZE_32+1, PSA_INITIAL_ATTEST_CHALLENGE_SIZE_32+1, - TOKEN_SIZE, PSA_ATTEST_ERR_INVALID_INPUT -}, - -{"Test psa_initial_attestation_get_token with large challenge size\n", - MAX_CHALLENGE_SIZE+1, MAX_CHALLENGE_SIZE+1, TOKEN_SIZE, PSA_ATTEST_ERR_INVALID_INPUT -}, - -{"Test psa_initial_attestation_get_token with zero as token size\n", - PSA_INITIAL_ATTEST_CHALLENGE_SIZE_32-1, PSA_INITIAL_ATTEST_CHALLENGE_SIZE_32, - 0, PSA_ATTEST_ERR_INVALID_INPUT -}, - -{"Test psa_initial_attestation_get_token with small token size\n", - PSA_INITIAL_ATTEST_CHALLENGE_SIZE_32-1, PSA_INITIAL_ATTEST_CHALLENGE_SIZE_32, - PSA_INITIAL_ATTEST_CHALLENGE_SIZE_32-1, PSA_ATTEST_ERR_TOKEN_BUFFER_OVERFLOW -}, -}; - -static test_data check2[] = { -{"Test psa_initial_attestation_get_token_size with Challenge 32\n", - PSA_INITIAL_ATTEST_CHALLENGE_SIZE_32, PSA_INITIAL_ATTEST_CHALLENGE_SIZE_32, TOKEN_SIZE, PSA_SUCCESS -}, - -{"Test psa_initial_attestation_get_token_size with Challenge 48\n", - PSA_INITIAL_ATTEST_CHALLENGE_SIZE_48, PSA_INITIAL_ATTEST_CHALLENGE_SIZE_48, TOKEN_SIZE, PSA_SUCCESS -}, - -{"Test psa_initial_attestation_get_token_size with Challenge 64\n", - PSA_INITIAL_ATTEST_CHALLENGE_SIZE_64, PSA_INITIAL_ATTEST_CHALLENGE_SIZE_64, TOKEN_SIZE, PSA_SUCCESS -}, - -{"Test psa_initial_attestation_get_token_size with zero challenge size\n", - 0, 0, - TOKEN_SIZE, PSA_ATTEST_ERR_INVALID_INPUT -}, - -{"Test psa_initial_attestation_get_token_size with small challenge size\n", - PSA_INITIAL_ATTEST_CHALLENGE_SIZE_32-1, PSA_INITIAL_ATTEST_CHALLENGE_SIZE_32-1, - TOKEN_SIZE, PSA_ATTEST_ERR_INVALID_INPUT -}, - -{"Test psa_initial_attestation_get_token_size with invalid challenge size\n", - PSA_INITIAL_ATTEST_CHALLENGE_SIZE_32+1, PSA_INITIAL_ATTEST_CHALLENGE_SIZE_32+1, - TOKEN_SIZE, PSA_ATTEST_ERR_INVALID_INPUT -}, - -{"Test psa_initial_attestation_get_token_size with large challenge size\n", - MAX_CHALLENGE_SIZE+1, MAX_CHALLENGE_SIZE+1, - TOKEN_SIZE, PSA_ATTEST_ERR_INVALID_INPUT -}, -}; diff --git a/components/TARGET_PSA/TESTS/compliance_attestation/test_a001/test_entry.c b/components/TARGET_PSA/TESTS/compliance_attestation/test_a001/test_entry.c deleted file mode 100644 index db253b8..0000000 --- a/components/TARGET_PSA/TESTS/compliance_attestation/test_a001/test_entry.c +++ /dev/null @@ -1,52 +0,0 @@ -/** @file - * Copyright (c) 2019, Arm Limited or its affiliates. All rights reserved. - * SPDX-License-Identifier : Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -**/ - -#include "val_interfaces.h" -#include "val_target.h" -#include "test_a001.h" - -#define TEST_NUM VAL_CREATE_TEST_ID(VAL_INITIAL_ATTESTATION_BASE, 1) -#define TEST_DESC "Testing initial attestation APIs\n" -TEST_PUBLISH(TEST_NUM, test_entry); -val_api_t *val = NULL; -psa_api_t *psa = NULL; - -void test_entry(val_api_t *val_api, psa_api_t *psa_api) -{ - int32_t status = VAL_STATUS_SUCCESS; - - val = val_api; - psa = psa_api; - - /* test init */ - val->test_init(TEST_NUM, TEST_DESC, TEST_FIELD(TEST_ISOLATION_L1, WD_HIGH_TIMEOUT)); - if (!IS_TEST_START(val->get_status())) - { - goto test_exit; - } - - /* Execute list of tests available in test[num]_attestation_list from Non-secure side*/ - status = val->execute_non_secure_tests(TEST_NUM, test_a001_attestation_list, FALSE); - - if (VAL_ERROR(status)) - { - goto test_exit; - } - -test_exit: - val->test_exit(); -} diff --git a/components/TARGET_PSA/TESTS/compliance_its/psa_its_testlist.md b/components/TARGET_PSA/TESTS/compliance_its/psa_its_testlist.md deleted file mode 100644 index b466a7e..0000000 --- a/components/TARGET_PSA/TESTS/compliance_its/psa_its_testlist.md +++ /dev/null @@ -1,30 +0,0 @@ -# PSA Internal Trusted Storage Testcase checklist - -## Requirements for Storage Test Suite - -Following are the requirements of the Storage Test Suite.
- -1. Unless described in this document, any behaviour that is defined as IMPLEMENTATION_DEFINED in PSA Storage API document is not verified in this document.
-2. Storage Test Cases use UID value starting from 1 onwards. These UID needs to be free for successfull test execution.
-3. UID values 1 and 2 are reserved as WRITE_ONCE UID.These UID can't be free from testcase. Make sure these are free.
- - -| Test | Return Value | API Verified | Test Algorithm | UID Usage | -|-----------|--------------------------------------|------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| test_s001 | PSA_ITS_ERROR_UID_NOT_FOUND | psa_its_get
psa_its_get_info
psa_its_remove
| 1. Call get API with UID for which no UID/Data pair is created
2. Call get_info API for which no UID/Data pair is created
3. Call remove API for which no UID/Data pair is created
4. Set valid UID/Data pair with uid1
5. Set one more set of UID/Data pair, with different uid, than previous
6. Remove the uid of step 4.
7. Call get API for removed UID/data pair
8. Call get_info API for removed UID/Data pair
9. Call remove API for removed UID/Data pair
10. Set valid UID/Data pair
11. Call get API for different uid , then created
12. Call get_info API for different uid, then created
13. Call remove API for different uid, then created
14. Remove the created UID/Data pair.
15. Remove the stray uid.
| UID value used are 5,6,7 | -| test_s002 | PSA_ITS_ERROR_WRITE_ONCE | psa_its_set
psa_its_remove
| 1. Set valid UID/data value pair , with create flag value none.2. Call get and get_info API to validate the data, attributes associated with data
3. Call set API again with same uid and create flag PSA_PS_WRITE_ONCE_FLAG
4. Call get and get_info API to validate the data, attributes associated with data is not changed after second set operation
5. try to remove the UID/data pair.
6. Create new UID/data value pair, with create flag PSA_PS_WRITE_ONCE_FLAG
7. Try to remove the created UID.
8. Call get and get_info API to validate the data, attributes associated with data
9. Again call SET with same UID , create flag PSA_PS_WRITE_ONCE_FLAG but different data length
10. Try to remove the UID, PSA_ITS_ERROR_WRITE_ONCE error should be returned
11. Call get and get_info API to validate the data, attributes associated with data
| UID value used are 1 and 2 | -| test_s003 | PSA_ITS_ERROR_INSUFFICIENT_SPACE | psa_its_set
| 1. Create UID/data pairs, with data_len 256 bytes. Do this with incrementing uid values till we have INSUFFICENT_SPACE.
2. Remove all the UID/data pairs created.
3. Repeat the steps once more, to check all previous uid are removed successfully
| UID value starts from 5 and keep on incrementing till all space is exhausted | -| test_s004 | PSA_ITS_SUCCESS | psa_its_set
psa_its_get
psa_its_get_info
psa_its_remove
| 1. Set a valid uid/data pair
2. Validate the data using get api
3. Change the data length to half of previous.
4. Call GET api with original data length , error should be returned and also the return buffer should be empty
5. Call GET api with correct data_len and validate the data received.
6. Check old data cannot be accessed.
7. Call REMOVE api to delete the UID/data pair
| UID value used is 5 | -| test_s005 | PSA_ITS_SUCCESS | psa_its_set
psa_its_get
psa_its_get_info
psa_its_remove
| 1. Set valid UID/data pair with varying uid and data_len
2. Call GET api and validate the set data
3. Call GET info api and validate the data attributes
4. Call REMOVE api to delete the UID/data pair
| UID value used are 4 | -| test_s006 | PSA_ITS_ERROR_FLAGS_NOT_SUPPORTED | psa_its_set
| 1. Call the SET_INFO with minimum flag value to max flag value
2. Call GET_INFO api and validate the flag value
3. Remove the uid/data pair
| UID value used is 5 | -| test_s007 | PSA_ITS_ERROR_INCORRECT_SIZE | psa_its_set
| 1. Create valid uid/data pair.
2. Increase the length of storage.
3. Try to access the old length using get api.
4. Try to access with valid length less than stored size.
5. Decrease the length of storage.
6. Try to access the old length.
7. Remove the uid
| UID value used is 5 | -| test_s008 | PSA_ITS_ERROR_OFFSET_INVALID | psa_its_get
| 1. Set valid UID/data pair
2. Call GET api with valid offset and offset + data_len equal to stored data size.
3. Call GET api with valid offset and offset + data_len less than stored data size.
4. Call get api with invalid offset.
5. Call get api with zero offset , but data len greater than data size.
6. Remove the uid.
| UID value used is 5 | -| test_s009 | PSA_ITS_SUCCESS | psa_its_get
psa_its_set
psa_its_get_info
| 1. Call the SET API with NULL pointer and data_len zero
2. Validate using get_info api storage should be present.
3. Call get API with NULL pointer.
4. Remove the UID.
5. Call get_info API to validate storage is removed.
6. Set storage entity with valid write_buffer , but length zero.
7. Call get_info API to validate storage attributes.
8. Call get_info api with NULL pointer and valid uid.
9. Remove the uid
| UID value used is 5
| -| test_s010 | PSA_ITS_ERROR_STORAGE_FAILURE
| psa_its_set
| 1. Call the SET API with UID value 0.
2. Check that storage creation fails.
| UID value used is 0
| - -## License -Arm PSA test suite is distributed under Apache v2.0 License. - --------------- - -*Copyright (c) 2019, Arm Limited and Contributors. All rights reserved.* diff --git a/components/TARGET_PSA/TESTS/compliance_its/test_s001/main.c b/components/TARGET_PSA/TESTS/compliance_its/test_s001/main.c deleted file mode 100644 index 2ab8343..0000000 --- a/components/TARGET_PSA/TESTS/compliance_its/test_s001/main.c +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2020, Arm Limited and affiliates. - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include "val_interfaces.h" -#include "pal_mbed_os_intf.h" - -#if !defined(MBED_CONF_RTOS_PRESENT) -#error [NOT_SUPPORTED] PSA compliance its test cases require RTOS to run -#else - -#ifdef ITS_TEST -void test_entry_s001(val_api_t *val_api, psa_api_t *psa_api); -#elif PS_TEST -void test_entry_p001(val_api_t *val_api, psa_api_t *psa_api); -#endif - -int main(void) -{ -#ifdef ITS_TEST - test_start(test_entry_s001, COMPLIANCE_TEST_STORAGE); -#elif PS_TEST - test_start(test_entry_p001, COMPLIANCE_TEST_STORAGE); -#endif -} -#endif // !defined(MBED_CONF_RTOS_PRESENT) diff --git a/components/TARGET_PSA/TESTS/compliance_its/test_s001/test_entry.c b/components/TARGET_PSA/TESTS/compliance_its/test_s001/test_entry.c deleted file mode 100644 index 8b8aed9..0000000 --- a/components/TARGET_PSA/TESTS/compliance_its/test_s001/test_entry.c +++ /dev/null @@ -1,53 +0,0 @@ -/** @file - * Copyright (c) 2019, Arm Limited or its affiliates. All rights reserved. - * SPDX-License-Identifier : Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -**/ - -#include "val_interfaces.h" -#include "val_target.h" -#include "test_s001.h" - -#define TEST_NUM VAL_CREATE_TEST_ID(VAL_STORAGE_BASE, 1) -#define TEST_DESC "UID not found check\n" - -TEST_PUBLISH(TEST_NUM, test_entry); -val_api_t *val = NULL; -psa_api_t *psa = NULL; - -void test_entry(val_api_t *val_api, psa_api_t *psa_api) -{ - int32_t status = VAL_STATUS_SUCCESS; - - val = val_api; - psa = psa_api; - - /* test init */ - val->test_init(TEST_NUM, TEST_DESC, TEST_FIELD(TEST_ISOLATION_L1, WD_HIGH_TIMEOUT)); - if (!IS_TEST_START(val->get_status())) - { - goto test_exit; - } - - /* Execute list of tests available in test[num]_secure_storage_list from Non-secure side*/ - status = val->execute_non_secure_tests(TEST_NUM, test_s001_sst_list, FALSE); - - if (VAL_ERROR(status)) - { - goto test_exit; - } - -test_exit: - val->test_exit(); -} diff --git a/components/TARGET_PSA/TESTS/compliance_its/test_s001/test_its_data.h b/components/TARGET_PSA/TESTS/compliance_its/test_s001/test_its_data.h deleted file mode 100644 index af95d04..0000000 --- a/components/TARGET_PSA/TESTS/compliance_its/test_s001/test_its_data.h +++ /dev/null @@ -1,81 +0,0 @@ -/** @file - * Copyright (c) 2019, Arm Limited or its affiliates. All rights reserved. - * SPDX-License-Identifier : Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -**/ -#ifndef _TEST_S001_ITS_DATA_TESTS_H_ -#define _TEST_S001_ITS_DATA_TESTS_H_ - -#include "val_internal_trusted_storage.h" - -#define SST_FUNCTION val->its_function -#define psa_sst_uid_t psa_its_uid_t - -typedef struct { - enum its_function_code api; - psa_its_status_t status; -} test_data; - -static struct psa_its_info_t info; -static const test_data s001_data[] = { -{ - 0, 0 /* Unused Index0 */ -}, -{ - VAL_ITS_GET, PSA_ITS_ERROR_UID_NOT_FOUND /* Call the get API when no UID is set */ -}, -{ - VAL_ITS_GET_INFO, PSA_ITS_ERROR_UID_NOT_FOUND /* Call the get_info API when no UID is set */ -}, -{ - VAL_ITS_REMOVE, PSA_ITS_ERROR_UID_NOT_FOUND /* Call the remove API when no UID is set */ -}, -{ - VAL_ITS_SET, PSA_ITS_SUCCESS /* Create a valid storage entity with UID1 */ -}, -{ - VAL_ITS_SET, PSA_ITS_SUCCESS /* Create a valid storage entity with UID2 */ -}, -{ - VAL_ITS_REMOVE, PSA_ITS_SUCCESS /* Remove UID1 */ -}, -{ - VAL_ITS_GET, PSA_ITS_ERROR_UID_NOT_FOUND /* Call get API for UID1 */ -}, -{ - VAL_ITS_GET_INFO, PSA_ITS_ERROR_UID_NOT_FOUND /* Call get_info API for UID1 */ -}, -{ - VAL_ITS_REMOVE, PSA_ITS_ERROR_UID_NOT_FOUND /* Call remove API for UID1 */ -}, -{ - VAL_ITS_SET, PSA_ITS_SUCCESS /* Create a valid storage entity again with UID1 */ -}, -{ - VAL_ITS_GET, PSA_ITS_ERROR_UID_NOT_FOUND /* Call get API for UID not same as UID1 or UID2 */ -}, -{ - VAL_ITS_GET_INFO, PSA_ITS_ERROR_UID_NOT_FOUND /* Call get_info for UID not same as UID1 or UID2 */ -}, -{ - VAL_ITS_REMOVE, PSA_ITS_ERROR_UID_NOT_FOUND /* Call remove API for UID not same as UID1 or UID2 */ -}, -{ - VAL_ITS_REMOVE, PSA_ITS_SUCCESS /* Remove UID1 */ -}, -{ - VAL_ITS_REMOVE, PSA_ITS_SUCCESS /* Remove UID2 */ -}, -}; -#endif /* _TEST_S001_ITS_DATA_TESTS_H_ */ diff --git a/components/TARGET_PSA/TESTS/compliance_its/test_s001/test_ps_data.h b/components/TARGET_PSA/TESTS/compliance_its/test_s001/test_ps_data.h deleted file mode 100644 index 2013058..0000000 --- a/components/TARGET_PSA/TESTS/compliance_its/test_s001/test_ps_data.h +++ /dev/null @@ -1,81 +0,0 @@ -/** @file - * Copyright (c) 2019, Arm Limited or ps affiliates. All rights reserved. - * SPDX-License-Identifier : Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -**/ -#ifndef _TEST_S001_PS_DATA_TESTS_H_ -#define _TEST_S001_PS_DATA_TESTS_H_ - -#include "val_protected_storage.h" - -#define SST_FUNCTION val->ps_function -#define psa_sst_uid_t psa_ps_uid_t - -typedef struct { - enum ps_function_code api; - psa_ps_status_t status; -} test_data; - -static struct psa_ps_info_t info; -static const test_data s001_data[] = { -{ - 0, 0 /* This is dummy for index0 */ -}, -{ - VAL_PS_GET, PSA_PS_ERROR_UID_NOT_FOUND /* Call the get API when no UID is set */ -}, -{ - VAL_PS_GET_INFO, PSA_PS_ERROR_UID_NOT_FOUND /* Call the get_info API when no UID is set */ -}, -{ - VAL_PS_REMOVE, PSA_PS_ERROR_UID_NOT_FOUND /* Call the remove API when no UID is set */ -}, -{ - VAL_PS_SET, PSA_PS_SUCCESS /* Create a valid storage entity with UID1 */ -}, -{ - VAL_PS_SET, PSA_PS_SUCCESS /* Create a valid storage entity with UID2 */ -}, -{ - VAL_PS_REMOVE, PSA_PS_SUCCESS /* Remove UID1 */ -}, -{ - VAL_PS_GET, PSA_PS_ERROR_UID_NOT_FOUND /* Call get API for UID1 */ -}, -{ - VAL_PS_GET_INFO, PSA_PS_ERROR_UID_NOT_FOUND /* Call get_info API for UID1 */ -}, -{ - VAL_PS_REMOVE, PSA_PS_ERROR_UID_NOT_FOUND /* Call remove API for UID1 */ -}, -{ - VAL_PS_SET, PSA_PS_SUCCESS /* Create a valid storage entity again with UID1 */ -}, -{ - VAL_PS_GET, PSA_PS_ERROR_UID_NOT_FOUND /* Call get API for UID not same as UID1 or UID2 */ -}, -{ - VAL_PS_GET_INFO, PSA_PS_ERROR_UID_NOT_FOUND /* Call get_info for UID not same as UID1 or UID2 */ -}, -{ - VAL_PS_REMOVE, PSA_PS_ERROR_UID_NOT_FOUND /* Call remove API for UID not same as UID1 or UID2 */ -}, -{ - VAL_PS_REMOVE, PSA_PS_SUCCESS /* Remove UID1 */ -}, -{ - VAL_PS_REMOVE, PSA_PS_SUCCESS /* Remove UID2 */ -}, -}; -#endif /* _TEST_S001_PS_DATA_TESTS_H_ */ diff --git a/components/TARGET_PSA/TESTS/compliance_its/test_s001/test_s001.c b/components/TARGET_PSA/TESTS/compliance_its/test_s001/test_s001.c deleted file mode 100644 index 5e9c26f..0000000 --- a/components/TARGET_PSA/TESTS/compliance_its/test_s001/test_s001.c +++ /dev/null @@ -1,170 +0,0 @@ -/** @file - * Copyright (c) 2019, Arm Limited or its affiliates. All rights reserved. - * SPDX-License-Identifier : Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -**/ - -#include "val_interfaces.h" -#include "val_target.h" -#include "test_s001.h" -#ifdef ITS_TEST -#include "test_its_data.h" -#elif PS_TEST -#include "test_ps_data.h" -#endif - -#define TEST_BUFF_SIZE 16 - -client_test_t test_s001_sst_list[] = { - NULL, - psa_sst_uid_not_found, - NULL, -}; - -static uint8_t write_buff[TEST_BUFF_SIZE] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F}; -static uint8_t read_buff[TEST_BUFF_SIZE] = {0}; - -static int32_t sst_calls_without_set_call(psa_sst_uid_t p_uid) -{ - uint32_t status; - - /* get() without using set() before */ - val->print(PRINT_TEST, "[Check 1] Call get API for UID %d which is not set\n", p_uid); - status = SST_FUNCTION(s001_data[1].api, p_uid, 0, TEST_BUFF_SIZE, read_buff); - TEST_ASSERT_EQUAL(status,s001_data[1].status,TEST_CHECKPOINT_NUM(1)); - - /* get_info() without using set() before */ - val->print(PRINT_TEST, "[Check 2] Call get_info API for UID %d which is not set\n", p_uid); - status = SST_FUNCTION(s001_data[2].api, p_uid, &info); - TEST_ASSERT_EQUAL(status, s001_data[2].status, TEST_CHECKPOINT_NUM(2)); - - /* remove() without using set() before */ - val->print(PRINT_TEST, "[Check 3] Call remove API for UID %d which is not set\n", p_uid); - status = SST_FUNCTION(s001_data[3].api, p_uid); - TEST_ASSERT_EQUAL(status, s001_data[3].status, TEST_CHECKPOINT_NUM(3)); - - return VAL_STATUS_SUCCESS; -} - -static int32_t sst_set_and_remove(psa_sst_uid_t p_uid) -{ - uint32_t status; - - /* set() a UID1 */ - status = SST_FUNCTION(s001_data[4].api, p_uid, TEST_BUFF_SIZE, write_buff, 0); - TEST_ASSERT_EQUAL(status, s001_data[4].status, TEST_CHECKPOINT_NUM(4)); - - /* Also set() with a different UID */ - status = SST_FUNCTION(s001_data[5].api, p_uid + 1, TEST_BUFF_SIZE, write_buff, 0); - TEST_ASSERT_EQUAL(status, s001_data[5].status, TEST_CHECKPOINT_NUM(5)); - - /* remove() UID1 */ - status = SST_FUNCTION(s001_data[6].api, p_uid); - TEST_ASSERT_EQUAL(status, s001_data[6].status, TEST_CHECKPOINT_NUM(6)); - - return VAL_STATUS_SUCCESS; -} - -static int32_t sst_calls_after_uid_remove(psa_sst_uid_t p_uid) -{ - uint32_t status; - - /* get() for UID which is removed */ - val->print(PRINT_TEST, "[Check 4] Call get API for UID %d which is removed\n", p_uid); - status = SST_FUNCTION(s001_data[7].api, p_uid, 0, TEST_BUFF_SIZE, read_buff); - TEST_ASSERT_EQUAL(status, s001_data[7].status, TEST_CHECKPOINT_NUM(7)); - - /* get_info() for UID which is removed */ - val->print(PRINT_TEST, "[Check 5] Call get_info API for UID %d which is removed\n", p_uid); - status = SST_FUNCTION(s001_data[8].api, p_uid, &info); - TEST_ASSERT_EQUAL(status, s001_data[8].status, TEST_CHECKPOINT_NUM(8)); - - /* remove() for UID which is removed */ - val->print(PRINT_TEST, "[Check 6] Call remove API for UID %d which is removed\n", p_uid); - status = SST_FUNCTION(s001_data[9].api, p_uid); - TEST_ASSERT_EQUAL(status, s001_data[9].status, TEST_CHECKPOINT_NUM(9)); - - return VAL_STATUS_SUCCESS; -} - -static int32_t sst_calls_with_different_uid(psa_sst_uid_t p_uid) -{ - uint32_t status; - - /* set() a UID */ - val->print(PRINT_TEST, "Set storage for UID %d\n", p_uid); - status = SST_FUNCTION(s001_data[10].api, p_uid, TEST_BUFF_SIZE, write_buff, 0); - TEST_ASSERT_EQUAL(status, s001_data[10].status, TEST_CHECKPOINT_NUM(10)); - - /* get() for different UID then set UID */ - val->print(PRINT_TEST, "[Check 7] Call get API for different UID %d\n", p_uid); - status = SST_FUNCTION(s001_data[11].api, p_uid-1, 0, TEST_BUFF_SIZE - 1, read_buff); - TEST_ASSERT_EQUAL(status, s001_data[11].status, TEST_CHECKPOINT_NUM(11)); - - /* get_info() for different UID then set UID */ - val->print(PRINT_TEST, "[Check 8] Call get_info API for different UID %d\n", p_uid); - status = SST_FUNCTION(s001_data[12].api, p_uid-1, &info); - TEST_ASSERT_EQUAL(status, s001_data[12].status, TEST_CHECKPOINT_NUM(12)); - - /* remove() for different UID then set UID */ - val->print(PRINT_TEST, "[Check 9] Call remove API for different UID %d\n", p_uid); - status = SST_FUNCTION(s001_data[13].api, p_uid-1); - TEST_ASSERT_EQUAL(status, s001_data[13].status, TEST_CHECKPOINT_NUM(13)); - - /* remove() the set UID */ - status = SST_FUNCTION(s001_data[14].api, p_uid); - TEST_ASSERT_EQUAL(status, s001_data[14].status, TEST_CHECKPOINT_NUM(14)); - - return VAL_STATUS_SUCCESS; -} - -static int32_t sst_remove_stray_uid(psa_sst_uid_t p_uid) -{ - uint32_t status; - - /* Remove UID + 1 */ - status = SST_FUNCTION(s001_data[15].api, p_uid); - TEST_ASSERT_EQUAL(status, s001_data[15].status, TEST_CHECKPOINT_NUM(15)); - - return VAL_STATUS_SUCCESS; -} - -int32_t psa_sst_uid_not_found(caller_security_t caller) -{ - int32_t test_status; - psa_sst_uid_t uid = UID_BASE_VALUE + 6; - - test_status = sst_calls_without_set_call(uid); - if (test_status != VAL_STATUS_SUCCESS) - return test_status; - - test_status = sst_set_and_remove(uid); - if (test_status != VAL_STATUS_SUCCESS) - return test_status; - - test_status = sst_calls_after_uid_remove(uid); - if (test_status != VAL_STATUS_SUCCESS) - return test_status; - - test_status = sst_calls_with_different_uid(uid); - if (test_status != VAL_STATUS_SUCCESS) - return test_status; - - test_status = sst_remove_stray_uid(uid + 1); - if (test_status != VAL_STATUS_SUCCESS) - return test_status; - - return VAL_STATUS_SUCCESS; -} diff --git a/components/TARGET_PSA/TESTS/compliance_its/test_s001/test_s001.h b/components/TARGET_PSA/TESTS/compliance_its/test_s001/test_s001.h deleted file mode 100644 index 08e5691..0000000 --- a/components/TARGET_PSA/TESTS/compliance_its/test_s001/test_s001.h +++ /dev/null @@ -1,35 +0,0 @@ -/** @file - * Copyright (c) 2019, Arm Limited or its affiliates. All rights reserved. - * SPDX-License-Identifier : Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -**/ -#ifndef _TEST_S001_CLIENT_TESTS_H_ -#define _TEST_S001_CLIENT_TESTS_H_ - -#ifdef ITS_TEST -#define VAL_STORAGE_BASE VAL_INTERNAL_TRUSTED_STORAGE_BASE -#define test_entry CONCAT(test_entry_, s001) -#elif PS_TEST -#define VAL_STORAGE_BASE VAL_PROTECTED_STORAGE_BASE -#define test_entry CONCAT(test_entry_, p001) -#endif -#define val CONCAT(val,test_entry) -#define psa CONCAT(psa,test_entry) - -extern val_api_t *val; -extern psa_api_t *psa; -extern client_test_t test_s001_sst_list[]; - -int32_t psa_sst_uid_not_found(caller_security_t caller); -#endif /* _TEST_S001_CLIENT_TESTS_H_ */ diff --git a/components/TARGET_PSA/TESTS/compliance_its/test_s002/main.c b/components/TARGET_PSA/TESTS/compliance_its/test_s002/main.c deleted file mode 100644 index 46729ac..0000000 --- a/components/TARGET_PSA/TESTS/compliance_its/test_s002/main.c +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2020, Arm Limited and affiliates. - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include "val_interfaces.h" -#include "pal_mbed_os_intf.h" -#include "lifecycle.h" -#if !defined(MBED_CONF_RTOS_PRESENT) -#error [NOT_SUPPORTED] PSA compliance its test cases require RTOS to run -#else - -#ifdef ITS_TEST -void test_entry_s002(val_api_t *val_api, psa_api_t *psa_api); -#elif PS_TEST -void test_entry_p002(val_api_t *val_api, psa_api_t *psa_api); -#endif - -int main(void) -{ -#ifdef ITS_TEST - test_start(test_entry_s002, COMPLIANCE_TEST_STORAGE); -#elif PS_TEST - test_start(test_entry_p002, COMPLIANCE_TEST_STORAGE); -#endif -} -#endif // !defined(MBED_CONF_RTOS_PRESENT) diff --git a/components/TARGET_PSA/TESTS/compliance_its/test_s002/test_entry.c b/components/TARGET_PSA/TESTS/compliance_its/test_s002/test_entry.c deleted file mode 100644 index 538a41f..0000000 --- a/components/TARGET_PSA/TESTS/compliance_its/test_s002/test_entry.c +++ /dev/null @@ -1,53 +0,0 @@ -/** @file - * Copyright (c) 2019, Arm Limited or its affiliates. All rights reserved. - * SPDX-License-Identifier : Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -**/ - -#include "val_interfaces.h" -#include "val_target.h" -#include "test_s002.h" - -#define TEST_NUM VAL_CREATE_TEST_ID(VAL_STORAGE_BASE, 2) -#define TEST_DESC "Write once error check\n" - -TEST_PUBLISH(TEST_NUM, test_entry); -val_api_t *val = NULL; -psa_api_t *psa = NULL; - -void test_entry(val_api_t *val_api, psa_api_t *psa_api) -{ - int32_t status = VAL_STATUS_SUCCESS; - - val = val_api; - psa = psa_api; - - /* test init */ - val->test_init(TEST_NUM, TEST_DESC, TEST_FIELD(TEST_ISOLATION_L1, WD_HIGH_TIMEOUT)); - if (!IS_TEST_START(val->get_status())) - { - goto test_exit; - } - - /* Execute list of tests available in test[num]_secure_storage_list from Non-secure side*/ - status = val->execute_non_secure_tests(TEST_NUM, test_s002_sst_list, FALSE); - - if (VAL_ERROR(status)) - { - goto test_exit; - } - -test_exit: - val->test_exit(); -} diff --git a/components/TARGET_PSA/TESTS/compliance_its/test_s002/test_its_data.h b/components/TARGET_PSA/TESTS/compliance_its/test_s002/test_its_data.h deleted file mode 100644 index 303b25f..0000000 --- a/components/TARGET_PSA/TESTS/compliance_its/test_s002/test_its_data.h +++ /dev/null @@ -1,134 +0,0 @@ -/** @file - * Copyright (c) 2019, Arm Limited or its affiliates. All rights reserved. - * SPDX-License-Identifier : Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -**/ -#ifndef _TEST_S002_ITS_DATA_TESTS_H_ -#define _TEST_S002_ITS_DATA_TESTS_H_ - -#include "val_internal_trusted_storage.h" - -#define SST_FUNCTION val->its_function -#define PSA_SST_FLAG_WRITE_ONCE PSA_ITS_FLAG_WRITE_ONCE -#define psa_sst_uid_t psa_its_uid_t - -typedef struct { - enum its_function_code api; - psa_its_status_t status; -} test_data; - -static struct psa_its_info_t orig_info; -static struct psa_its_info_t new_info; -static const test_data s002_data[] = { -{ - 0, 0 /* This is dummy for index0 */ -}, -{ - VAL_ITS_SET, PSA_ITS_SUCCESS /* Create a valid storage with create flag value 0 */ -}, -{ - VAL_ITS_GET_INFO, PSA_ITS_SUCCESS /* Call the get_info API to validate the attributes */ -}, -{ - 0, 0 /* Index not used as check for get info size */ -}, -{ - 0, 0 /* Index not used as check for get info flag */ -}, -{ - VAL_ITS_GET, PSA_ITS_SUCCESS /* Validate the data using get API */ -}, -{ - 0, 0 /* Index not used */ -}, -{ - VAL_ITS_SET, PSA_ITS_SUCCESS /* Change the flag to WRITE_ONCE using set API */ -}, -{ - VAL_ITS_GET_INFO, PSA_ITS_SUCCESS /* Call the get_info API to validate the flag change */ -}, -{ - 0, 0 /* Index not used as check for get info size */ -}, -{ - 0, 0 /* Index not used as check for get info flag */ -}, -{ - VAL_ITS_GET, PSA_ITS_SUCCESS /* Validate the data using get API after flag change */ -}, -{ - 0, 0 /* Index not used */ -}, -{ - VAL_ITS_REMOVE, PSA_ITS_ERROR_WRITE_ONCE /* Storage should not be removed after WRITE_ONCE flag */ -}, -{ - VAL_ITS_SET, PSA_ITS_SUCCESS /* Create a storage with different UID and flag value WRITE_ONCE */ -}, -{ - VAL_ITS_REMOVE, PSA_ITS_ERROR_WRITE_ONCE /* Storage should not be removed */ -}, -{ - VAL_ITS_GET, PSA_ITS_SUCCESS /* Validate the data using get API after flag change */ -}, -{ - 0, 0 /* Index not used */ -}, -{ - VAL_ITS_GET_INFO, PSA_ITS_SUCCESS /* Call the get_info API to validate the flag change */ -}, -{ - 0, 0 /* Index not used as check for get info size */ -}, -{ - 0, 0 /* Index not used as check for get info flag */ -}, -{ - VAL_ITS_SET, PSA_ITS_ERROR_WRITE_ONCE /* Try to set different size for same UID and flag value */ -}, -{ - VAL_ITS_REMOVE, PSA_ITS_ERROR_WRITE_ONCE /* Storage should not be removed */ -}, -{ - VAL_ITS_GET_INFO, PSA_ITS_SUCCESS /* Call the get_info API to validate the flag change */ -}, -{ - 0, 0 /* Index not used as check for get info size */ -}, -{ - 0, 0 /* Index not used as check for get info flag */ -}, -{ - VAL_ITS_GET, PSA_ITS_SUCCESS /* Validate the data using get API after flag change */ -}, -{ - 0, 0 /* Index not used */ -}, -{ - VAL_ITS_SET, PSA_ITS_ERROR_WRITE_ONCE /* Setting flag to zero for UID should fail */ -}, -{ - VAL_ITS_REMOVE, PSA_ITS_ERROR_WRITE_ONCE /* Storage should not be removed */ -}, -{ - VAL_ITS_GET_INFO, PSA_ITS_SUCCESS /* Check that the WRITE_ONCE flag is preserved */ -}, -{ - 0, 0 /* Index not used as check for get info size */ -}, -{ - 0, 0 /* Index not used as check for get info flag */ -}, -}; -#endif /* _TEST_S002_ITS_DATA_TESTS_H_ */ diff --git a/components/TARGET_PSA/TESTS/compliance_its/test_s002/test_ps_data.h b/components/TARGET_PSA/TESTS/compliance_its/test_s002/test_ps_data.h deleted file mode 100644 index 19e88b7..0000000 --- a/components/TARGET_PSA/TESTS/compliance_its/test_s002/test_ps_data.h +++ /dev/null @@ -1,134 +0,0 @@ -/** @file - * Copyright (c) 2019, Arm Limited or ps affiliates. All rights reserved. - * SPDX-License-Identifier : Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -**/ -#ifndef _TEST_S002_PS_DATA_TESTS_H_ -#define _TEST_S002_PS_DATA_TESTS_H_ - -#include "val_protected_storage.h" - -#define SST_FUNCTION val->ps_function -#define PSA_SST_FLAG_WRITE_ONCE PSA_PS_FLAG_WRITE_ONCE -#define psa_sst_uid_t psa_ps_uid_t - -typedef struct { - enum ps_function_code api; - psa_ps_status_t status; -} test_data; - -static struct psa_ps_info_t orig_info; -static struct psa_ps_info_t new_info; -static const test_data s002_data[] = { -{ - 0, 0 /* This is dummy for index0 */ -}, -{ - VAL_PS_SET, PSA_PS_SUCCESS /* Create a valid storage with create flag value 0 */ -}, -{ - VAL_PS_GET_INFO, PSA_PS_SUCCESS /* Call the get_info API to validate the attributes */ -}, -{ - 0, 0 /* Index not used as check for get info size */ -}, -{ - 0, 0 /* Index not used as check for get info flag */ -}, -{ - VAL_PS_GET, PSA_PS_SUCCESS /* Validate the data using get API */ -}, -{ - 0, 0 /* Index not used */ -}, -{ - VAL_PS_SET, PSA_PS_SUCCESS /* Change the flag to WRITE_ONCE using set API */ -}, -{ - VAL_PS_GET_INFO, PSA_PS_SUCCESS /* Call the get_info API to validate the flag change */ -}, -{ - 0, 0 /* Index not used as check for get info size */ -}, -{ - 0, 0 /* Index not used as check for get info flag */ -}, -{ - VAL_PS_GET, PSA_PS_SUCCESS /* Validate the data using get API after flag change */ -}, -{ - 0, 0 /* Index not used */ -}, -{ - VAL_PS_REMOVE, PSA_PS_ERROR_WRITE_ONCE /* Storage should not be removed after WRITE_ONCE flag */ -}, -{ - VAL_PS_SET, PSA_PS_SUCCESS /* Create storage with different UID and flag value WRITE_ONCE */ -}, -{ - VAL_PS_REMOVE, PSA_PS_ERROR_WRITE_ONCE /* Storage should not be removed */ -}, -{ - VAL_PS_GET, PSA_PS_SUCCESS /* Validate the data using get API after flag change */ -}, -{ - 0, 0 /* Index not used */ -}, -{ - VAL_PS_GET_INFO, PSA_PS_SUCCESS /* Call the get_info API to validate the flag change */ -}, -{ - 0, 0 /* Index not used as check for get info size */ -}, -{ - 0, 0 /* Index not used as check for get info flag */ -}, -{ - VAL_PS_SET, PSA_PS_ERROR_WRITE_ONCE /* Try to set different size for same UID and flag value */ -}, -{ - VAL_PS_REMOVE, PSA_PS_ERROR_WRITE_ONCE /* Storage should not be removed */ -}, -{ - VAL_PS_GET_INFO, PSA_PS_SUCCESS /* Call the get_info API to validate the flag change */ -}, -{ - 0, 0 /* Index not used as check for get info size */ -}, -{ - 0, 0 /* Index not used as check for get info flag */ -}, -{ - VAL_PS_GET, PSA_PS_SUCCESS /* Validate the data using get API after flag change */ -}, -{ - 0, 0 /* Index not used */ -}, -{ - VAL_PS_SET, PSA_PS_ERROR_WRITE_ONCE /* Setting flag to zero for UID should fail */ -}, -{ - VAL_PS_REMOVE, PSA_PS_ERROR_WRITE_ONCE /* Storage should not be removed */ -}, -{ - VAL_PS_GET_INFO, PSA_PS_SUCCESS /* Check that the WRITE_ONCE flag is preserved */ -}, -{ - 0, 0 /* Index not used as check for get info size */ -}, -{ - 0, 0 /* Index not used as check for get info flag */ -}, -}; -#endif /* _TEST_S002_PS_DATA_TESTS_H_ */ diff --git a/components/TARGET_PSA/TESTS/compliance_its/test_s002/test_s002.c b/components/TARGET_PSA/TESTS/compliance_its/test_s002/test_s002.c deleted file mode 100644 index d46ace1..0000000 --- a/components/TARGET_PSA/TESTS/compliance_its/test_s002/test_s002.c +++ /dev/null @@ -1,161 +0,0 @@ -/** @file - * Copyright (c) 2019, Arm Limited or sst affiliates. All rights reserved. - * SPDX-License-Identifier : Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -**/ - -#include "val_interfaces.h" -#include "val_target.h" -#include "test_s002.h" -#ifdef ITS_TEST -#include "test_its_data.h" -#elif PS_TEST -#include "test_ps_data.h" -#endif - -#define UID_WRITE_ONCE_1 UID_BASE_VALUE + 1 -#define UID_WRITE_ONCE_2 UID_BASE_VALUE + 2 -#define TEST_BUFF_SIZE 16 - -client_test_t test_s002_sst_list[] = { - NULL, - psa_sst_update_write_once_flag_after_create, - psa_sst_create_with_write_once_flag, - NULL, -}; - -int32_t psa_sst_update_write_once_flag_after_create(caller_security_t caller) -{ - uint32_t status; - psa_sst_uid_t uid = UID_WRITE_ONCE_1; - uint8_t write_buff[TEST_BUFF_SIZE/2] = {0xDE, 0xAD, 0xBE, 0xEF, 0xCA, 0xFE, 0xBA, 0xBE}; - uint8_t read_buff[TEST_BUFF_SIZE/2] = {0}; - uint8_t write_buff_new[TEST_BUFF_SIZE/4] = {0xFF, 0xFF, 0xFF, 0xFF}; - - /* set() data without a WRITE_ONCE flag */ - status = SST_FUNCTION(s002_data[1].api, uid, TEST_BUFF_SIZE/2, write_buff, 0); - TEST_ASSERT_EQUAL(status, s002_data[1].status, TEST_CHECKPOINT_NUM(1)); - - /* Check that get_info() returns correct attributes; also store for reference for later */ - status = SST_FUNCTION(s002_data[2].api, uid, &orig_info); - TEST_ASSERT_EQUAL(status, s002_data[2].status, TEST_CHECKPOINT_NUM(2)); - TEST_ASSERT_EQUAL(orig_info.size, TEST_BUFF_SIZE/2, TEST_CHECKPOINT_NUM(3)); - TEST_ASSERT_EQUAL(orig_info.flags, 0, TEST_CHECKPOINT_NUM(4)); - - /* Check for data consistency using get() */ - status = SST_FUNCTION(s002_data[5].api, uid, 0, TEST_BUFF_SIZE/2, read_buff); - TEST_ASSERT_EQUAL(status, s002_data[5].status, TEST_CHECKPOINT_NUM(5)); - TEST_ASSERT_MEMCMP(write_buff, read_buff, TEST_BUFF_SIZE/2, TEST_CHECKPOINT_NUM(6)); - - /* set() with WRITE_ONCE_FLAG */ - val->print(PRINT_TEST, "[Check 1] Update the flag of UID %d with WRITE_ONCE flag\n", uid); - status = SST_FUNCTION(s002_data[7].api, uid, TEST_BUFF_SIZE/4, write_buff_new, - PSA_SST_FLAG_WRITE_ONCE); - TEST_ASSERT_EQUAL(status, s002_data[7].status, TEST_CHECKPOINT_NUM(7)); - - /* Check that info is updated, after new set */ - status = SST_FUNCTION(s002_data[8].api, uid, &new_info); - TEST_ASSERT_EQUAL(status, s002_data[8].status, TEST_CHECKPOINT_NUM(8)); - TEST_ASSERT_EQUAL(new_info.size, new_info.size, TEST_CHECKPOINT_NUM(9)); - TEST_ASSERT_EQUAL(new_info.flags, new_info.flags, TEST_CHECKPOINT_NUM(10)); - - /* Check that data contents are preserved which were written with WRITE_ONCE_FLAG originally */ - status = SST_FUNCTION(s002_data[11].api, uid, 0, TEST_BUFF_SIZE/4, read_buff); - TEST_ASSERT_EQUAL(status, s002_data[11].status, TEST_CHECKPOINT_NUM(11)); - TEST_ASSERT_MEMCMP(write_buff_new, read_buff, TEST_BUFF_SIZE/4, TEST_CHECKPOINT_NUM(12)); - - /* remove() the UID */ - val->print(PRINT_TEST, "[Check 2] Try to remove the UID %d having WRITE_ONCE flag\n", uid); - status = SST_FUNCTION(s002_data[13].api, uid); - TEST_ASSERT_EQUAL(status, s002_data[13].status, TEST_CHECKPOINT_NUM(13)); - - return VAL_STATUS_SUCCESS; -} - - -int32_t psa_sst_create_with_write_once_flag(caller_security_t caller) -{ - uint32_t status; - psa_sst_uid_t uid = UID_WRITE_ONCE_2; - uint8_t write_buff[TEST_BUFF_SIZE] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F}; - uint8_t read_buff[TEST_BUFF_SIZE] = {0}; - uint8_t write_buff_new[TEST_BUFF_SIZE + 1] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF}; - - /* Set data for a UID using WRITE_ONCE flag */ - val->print(PRINT_TEST, "[Check 3] Create a new UID %d with WRITE_ONCE flag\n", uid); - status = SST_FUNCTION(s002_data[14].api, uid, TEST_BUFF_SIZE, write_buff, - PSA_SST_FLAG_WRITE_ONCE); - TEST_ASSERT_EQUAL(status, s002_data[14].status, TEST_CHECKPOINT_NUM(14)); - - /* Check that remove() fails with PSA_SST_ERROR_WRITE_ONCE */ - val->print(PRINT_TEST, "[Check 4] Try to remove the UID %d having WRITE_ONCE flag\n", uid); - status = SST_FUNCTION(s002_data[15].api, uid); - TEST_ASSERT_EQUAL(status, s002_data[15].status, TEST_CHECKPOINT_NUM(15)); - - /* Check data consistency using get()*/ - status = SST_FUNCTION(s002_data[16].api, uid, 0, TEST_BUFF_SIZE, read_buff); - TEST_ASSERT_EQUAL(status, s002_data[16].status, TEST_CHECKPOINT_NUM(16)); - TEST_ASSERT_MEMCMP(write_buff, read_buff, TEST_BUFF_SIZE, TEST_CHECKPOINT_NUM(17)); - - /* Check that info values is as expected */ - status = SST_FUNCTION(s002_data[18].api, uid, &orig_info); - TEST_ASSERT_EQUAL(status, s002_data[18].status, TEST_CHECKPOINT_NUM(18)); - TEST_ASSERT_EQUAL(orig_info.size, TEST_BUFF_SIZE, TEST_CHECKPOINT_NUM(19)); - TEST_ASSERT_EQUAL(orig_info.flags, PSA_SST_FLAG_WRITE_ONCE, TEST_CHECKPOINT_NUM(20)); - - /* Try to overwrite using set() with same UID as used before with WRITE_ONCE_FLAG */ - val->print(PRINT_TEST, "[Check 5] Try to change the length of write_once UID %d\n", uid); - status = SST_FUNCTION(s002_data[21].api, uid, (TEST_BUFF_SIZE + 1), write_buff_new, - PSA_SST_FLAG_WRITE_ONCE); - TEST_ASSERT_EQUAL(status, s002_data[21].status, TEST_CHECKPOINT_NUM(21)); - - /* Check that remove() still fails with PSA_SST_ERROR_WRITE_ONCE */ - val->print(PRINT_TEST, "[Check 6] Check UID removal still fails\n", 0); - status = SST_FUNCTION(s002_data[22].api, uid); - TEST_ASSERT_EQUAL(status, s002_data[22].status, TEST_CHECKPOINT_NUM(22)); - - /* Check that info is preserved */ - status = SST_FUNCTION(s002_data[23].api, uid, &new_info); - TEST_ASSERT_EQUAL(status, s002_data[23].status, TEST_CHECKPOINT_NUM(23)); - TEST_ASSERT_EQUAL(new_info.size, orig_info.size, TEST_CHECKPOINT_NUM(24)); - TEST_ASSERT_EQUAL(new_info.flags, orig_info.flags, TEST_CHECKPOINT_NUM(25)); - - /* Check that data contents are preserved which were written with WRITE_ONCE_FLAG originally */ - status = SST_FUNCTION(s002_data[26].api, uid, 0, TEST_BUFF_SIZE, read_buff); - TEST_ASSERT_EQUAL(status, s002_data[26].status, TEST_CHECKPOINT_NUM(26)); - TEST_ASSERT_MEMCMP(write_buff, read_buff, TEST_BUFF_SIZE, TEST_CHECKPOINT_NUM(27)); - - /* Try to overwrite using set() with same UID as used before without WRITE_ONCE_FLAG */ - val->print(PRINT_TEST, "[Check 7] Try to change the WRITE_ONCE flag to None for UID %d\n", uid); - new_info.size = 0; - new_info.flags = 0; - status = SST_FUNCTION(s002_data[28].api, uid, (TEST_BUFF_SIZE - 1), write_buff_new, 0); - TEST_ASSERT_EQUAL(status, s002_data[28].status, TEST_CHECKPOINT_NUM(28)); - - /* Check that remove() still fails with PSA_SST_ERROR_WRITE_ONCE */ - val->print(PRINT_TEST, "[Check 8] Check UID removal still fails\n", 0); - status = SST_FUNCTION(s002_data[29].api, uid); - TEST_ASSERT_EQUAL(status, s002_data[29].status, TEST_CHECKPOINT_NUM(29)); - - /* Check that info is preserved */ - status = SST_FUNCTION(s002_data[30].api, uid, &new_info); - TEST_ASSERT_EQUAL(status, s002_data[30].status, TEST_CHECKPOINT_NUM(30)); - TEST_ASSERT_EQUAL(new_info.size, orig_info.size, TEST_CHECKPOINT_NUM(31)); - TEST_ASSERT_EQUAL(new_info.flags, orig_info.flags, TEST_CHECKPOINT_NUM(32)); - - return VAL_STATUS_SUCCESS; -} diff --git a/components/TARGET_PSA/TESTS/compliance_its/test_s002/test_s002.h b/components/TARGET_PSA/TESTS/compliance_its/test_s002/test_s002.h deleted file mode 100644 index 3a06eb9..0000000 --- a/components/TARGET_PSA/TESTS/compliance_its/test_s002/test_s002.h +++ /dev/null @@ -1,36 +0,0 @@ -/** @file - * Copyright (c) 2019, Arm Limited or its affiliates. All rights reserved. - * SPDX-License-Identifier : Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -**/ -#ifndef _TEST_S002_CLIENT_TESTS_H_ -#define _TEST_S002_CLIENT_TESTS_H_ - -#ifdef ITS_TEST -#define VAL_STORAGE_BASE VAL_INTERNAL_TRUSTED_STORAGE_BASE -#define test_entry CONCAT(test_entry_, s002) -#elif PS_TEST -#define VAL_STORAGE_BASE VAL_PROTECTED_STORAGE_BASE -#define test_entry CONCAT(test_entry_, p002) -#endif -#define val CONCAT(val,test_entry) -#define psa CONCAT(psa,test_entry) - -extern val_api_t *val; -extern psa_api_t *psa; -extern client_test_t test_s002_sst_list[]; - -int32_t psa_sst_update_write_once_flag_after_create(caller_security_t caller); -int32_t psa_sst_create_with_write_once_flag(caller_security_t caller); -#endif /* _TEST_S002_CLIENT_TESTS_H_ */ diff --git a/components/TARGET_PSA/TESTS/compliance_its/test_s003/main.c b/components/TARGET_PSA/TESTS/compliance_its/test_s003/main.c deleted file mode 100644 index fc7328c..0000000 --- a/components/TARGET_PSA/TESTS/compliance_its/test_s003/main.c +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2020, Arm Limited and affiliates. - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include "val_interfaces.h" -#include "pal_mbed_os_intf.h" -#include "lifecycle.h" - -#ifndef PS_ALLOW_ENTIRE_STORAGE_FILL -#error [NOT_SUPPORTED] Test is too long for CI, thus always fails on timeout. -#endif - -#ifdef ITS_TEST -void test_entry_s003(val_api_t *val_api, psa_api_t *psa_api); -#elif PS_TEST -void test_entry_p003(val_api_t *val_api, psa_api_t *psa_api); -#endif - -int main(void) -{ -#ifdef ITS_TEST - test_start(test_entry_s003, COMPLIANCE_TEST_STORAGE); -#elif PS_TEST - test_start(test_entry_p003, COMPLIANCE_TEST_STORAGE); -#endif - -} diff --git a/components/TARGET_PSA/TESTS/compliance_its/test_s003/test_entry.c b/components/TARGET_PSA/TESTS/compliance_its/test_s003/test_entry.c deleted file mode 100644 index 30dcbde..0000000 --- a/components/TARGET_PSA/TESTS/compliance_its/test_s003/test_entry.c +++ /dev/null @@ -1,53 +0,0 @@ -/** @file - * Copyright (c) 2019, Arm Limited or its affiliates. All rights reserved. - * SPDX-License-Identifier : Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -**/ - -#include "val_interfaces.h" -#include "val_target.h" -#include "test_s003.h" - -#define TEST_NUM VAL_CREATE_TEST_ID(VAL_STORAGE_BASE, 3) -#define TEST_DESC "Insufficient space check\n" - -TEST_PUBLISH(TEST_NUM, test_entry); -val_api_t *val = NULL; -psa_api_t *psa = NULL; - -void test_entry(val_api_t *val_api, psa_api_t *psa_api) -{ - int32_t status = VAL_STATUS_SUCCESS; - - val = val_api; - psa = psa_api; - - /* test init */ - val->test_init(TEST_NUM, TEST_DESC, TEST_FIELD(TEST_ISOLATION_L1, WD_HIGH_TIMEOUT)); - if (!IS_TEST_START(val->get_status())) - { - goto test_exit; - } - - /* Execute list of tests available in test[num]_secure_storage_list from Non-secure side*/ - status = val->execute_non_secure_tests(TEST_NUM, test_s003_sst_list, FALSE); - - if (VAL_ERROR(status)) - { - goto test_exit; - } - -test_exit: - val->test_exit(); -} diff --git a/components/TARGET_PSA/TESTS/compliance_its/test_s003/test_its_data.h b/components/TARGET_PSA/TESTS/compliance_its/test_s003/test_its_data.h deleted file mode 100644 index 511e418..0000000 --- a/components/TARGET_PSA/TESTS/compliance_its/test_s003/test_its_data.h +++ /dev/null @@ -1,42 +0,0 @@ -/** @file - * Copyright (c) 2019, Arm Limited or its affiliates. All rights reserved. - * SPDX-License-Identifier : Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -**/ -#ifndef _TEST_S003_ITS_DATA_TESTS_H_ -#define _TEST_S003_ITS_DATA_TESTS_H_ - -#include "val_internal_trusted_storage.h" - -#define SST_FUNCTION val->its_function -#define PSA_SST_SUCCESS PSA_ITS_SUCCESS -#define psa_sst_uid_t psa_its_uid_t - -typedef struct { - enum its_function_code api; - psa_its_status_t status; -} test_data; - -static const test_data s003_data[] = { -{ - 0, 0 /* This is dummy for index0 */ -}, -{ - VAL_ITS_SET, PSA_ITS_ERROR_INSUFFICIENT_SPACE /* Call set API till insufficent space */ -}, -{ - VAL_ITS_REMOVE, PSA_ITS_SUCCESS /* Remove the UID created */ -}, -}; -#endif /* _TEST_S003_ITS_DATA_TESTS_H_ */ diff --git a/components/TARGET_PSA/TESTS/compliance_its/test_s003/test_ps_data.h b/components/TARGET_PSA/TESTS/compliance_its/test_s003/test_ps_data.h deleted file mode 100644 index db48c35..0000000 --- a/components/TARGET_PSA/TESTS/compliance_its/test_s003/test_ps_data.h +++ /dev/null @@ -1,42 +0,0 @@ -/** @file - * Copyright (c) 2019, Arm Limited or ps affiliates. All rights reserved. - * SPDX-License-Identifier : Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -**/ -#ifndef _TEST_S003_PS_DATA_TESTS_H_ -#define _TEST_S003_PS_DATA_TESTS_H_ - -#include "val_protected_storage.h" - -#define SST_FUNCTION val->ps_function -#define PSA_SST_SUCCESS PSA_PS_SUCCESS -#define psa_sst_uid_t psa_ps_uid_t - -typedef struct { - enum ps_function_code api; - psa_ps_status_t status; -} test_data; - -static const test_data s003_data[] = { -{ - 0, 0 /* This is dummy for index0 */ -}, -{ - VAL_PS_SET, PSA_PS_ERROR_INSUFFICIENT_SPACE /* Call set API till insufficent space */ -}, -{ - VAL_PS_REMOVE, PSA_PS_SUCCESS /* Remove the UID created */ -}, -}; -#endif /* _TEST_S003_PS_DATA_TESTS_H_ */ diff --git a/components/TARGET_PSA/TESTS/compliance_its/test_s003/test_s003.c b/components/TARGET_PSA/TESTS/compliance_its/test_s003/test_s003.c deleted file mode 100644 index 3475075..0000000 --- a/components/TARGET_PSA/TESTS/compliance_its/test_s003/test_s003.c +++ /dev/null @@ -1,96 +0,0 @@ -/** @file - * Copyright (c) 2019, Arm Limited or its affiliates. All rights reserved. - * SPDX-License-Identifier : Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -**/ - -#include "val_interfaces.h" -#include "val_target.h" -#include "test_s003.h" -#if ITS_TEST -#include "test_its_data.h" -#elif PS_TEST -#include "test_ps_data.h" -#endif - -#define TEST_BUFF_SIZE 1024 -#define NUM_ITERATIONS 2 -#define TEST_BASE_UID_VALUE UID_BASE_VALUE + 5 - -client_test_t test_s003_sst_list[] = { - NULL, - psa_sst_insufficient_space, - NULL, -}; - -static uint8_t write_buff[TEST_BUFF_SIZE]; -static char test_desc[2][80] = { - "Overload storage space\n", - "Overload storage again to verify all previous UID removed\n"}; - -int32_t psa_sst_insufficient_space(caller_security_t caller) -{ - uint32_t status = PSA_SST_SUCCESS; - psa_sst_uid_t uid; - uint32_t count = 0, results[NUM_ITERATIONS] = {0}; - int i = 0; - - /* Saturate the storage for NUM_ITERATION times, and remove them after */ - for (i = 0 ; i < NUM_ITERATIONS; i++) - { - val->print(PRINT_TEST, "[Check %d] ", i + 1); - val->print(PRINT_TEST, &test_desc[i][0], 0); - for (uid = TEST_BASE_UID_VALUE; status == PSA_SST_SUCCESS; uid++) - { - val->print(PRINT_INFO, "Setting 0x%x bytes for ", TEST_BUFF_SIZE); - val->print(PRINT_INFO, "UID %d\n", uid); - status = SST_FUNCTION(s003_data[1].api, uid, TEST_BUFF_SIZE, write_buff, 0); - if (status != PSA_SST_SUCCESS) - { - val->print(PRINT_INFO, "UID %d set failed due to insufficient space\n", uid); - break; - } - } - TEST_ASSERT_EQUAL(status, s003_data[1].status, TEST_CHECKPOINT_NUM(1)); - - /* Store number of set()s it took to saturate the storage */ - count = uid - (TEST_BASE_UID_VALUE); - results[i] = uid - (TEST_BASE_UID_VALUE); - - if (count) - val->print(PRINT_TEST, "Remove all registered UIDs\n", 0); - for (uid = TEST_BASE_UID_VALUE; uid < (count + TEST_BASE_UID_VALUE); uid++) - { - val->print(PRINT_INFO, "Removing UID %d\n", uid); - status = SST_FUNCTION(s003_data[2].api, uid); - if (status != PSA_SST_SUCCESS) - break; - } - if (count) - TEST_ASSERT_EQUAL(status, s003_data[2].status, TEST_CHECKPOINT_NUM(2)); - } - - /* Check that it takes equal number of UIDs to fill up the storage each time */ - for (i = 0; i < (NUM_ITERATIONS -1); i++) - { - if (results[i] != results[i+1]) - { - val->print(PRINT_ERROR, "\tERROR : Mismatch between number of UIDs required to\n", 0); - val->print(PRINT_ERROR, "\t fill up the storage between iteration %d", i); - val->print(PRINT_ERROR, " and iteration %d\n", i+1); - return VAL_STATUS_ERROR; - } - } - return VAL_STATUS_SUCCESS; -} diff --git a/components/TARGET_PSA/TESTS/compliance_its/test_s003/test_s003.h b/components/TARGET_PSA/TESTS/compliance_its/test_s003/test_s003.h deleted file mode 100644 index 9fb4755..0000000 --- a/components/TARGET_PSA/TESTS/compliance_its/test_s003/test_s003.h +++ /dev/null @@ -1,35 +0,0 @@ -/** @file - * Copyright (c) 2019, Arm Limited or its affiliates. All rights reserved. - * SPDX-License-Identifier : Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -**/ -#ifndef _TEST_S003_CLIENT_TESTS_H_ -#define _TEST_S003_CLIENT_TESTS_H_ - -#ifdef ITS_TEST -#define VAL_STORAGE_BASE VAL_INTERNAL_TRUSTED_STORAGE_BASE -#define test_entry CONCAT(test_entry_, s003) -#elif PS_TEST -#define VAL_STORAGE_BASE VAL_PROTECTED_STORAGE_BASE -#define test_entry CONCAT(test_entry_, p003) -#endif -#define val CONCAT(val,test_entry) -#define psa CONCAT(psa,test_entry) - -extern val_api_t *val; -extern psa_api_t *psa; -extern client_test_t test_s003_sst_list[]; - -int32_t psa_sst_insufficient_space(caller_security_t caller); -#endif /* _TEST_S003_CLIENT_TESTS_H_ */ diff --git a/components/TARGET_PSA/TESTS/compliance_its/test_s004/main.c b/components/TARGET_PSA/TESTS/compliance_its/test_s004/main.c deleted file mode 100644 index 20a623e..0000000 --- a/components/TARGET_PSA/TESTS/compliance_its/test_s004/main.c +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2020, Arm Limited and affiliates. - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include "val_interfaces.h" -#include "pal_mbed_os_intf.h" -#if !defined(MBED_CONF_RTOS_PRESENT) -#error [NOT_SUPPORTED] PSA compliance its test cases require RTOS to run -#else - -#ifdef ITS_TEST -void test_entry_s004(val_api_t *val_api, psa_api_t *psa_api); -#elif PS_TEST -void test_entry_p004(val_api_t *val_api, psa_api_t *psa_api); -#endif - -int main(void) -{ -#ifdef ITS_TEST - test_start(test_entry_s004, COMPLIANCE_TEST_STORAGE); -#elif PS_TEST - test_start(test_entry_p004, COMPLIANCE_TEST_STORAGE); -#endif -} -#endif // !defined(MBED_CONF_RTOS_PRESENT) diff --git a/components/TARGET_PSA/TESTS/compliance_its/test_s004/test_entry.c b/components/TARGET_PSA/TESTS/compliance_its/test_s004/test_entry.c deleted file mode 100644 index a6afc24..0000000 --- a/components/TARGET_PSA/TESTS/compliance_its/test_s004/test_entry.c +++ /dev/null @@ -1,53 +0,0 @@ -/** @file - * Copyright (c) 2019, Arm Limited or its affiliates. All rights reserved. - * SPDX-License-Identifier : Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -**/ - -#include "val_interfaces.h" -#include "val_target.h" -#include "test_s004.h" - -#define TEST_NUM VAL_CREATE_TEST_ID(VAL_STORAGE_BASE, 4) -#define TEST_DESC "Data Consistency check\n" - -TEST_PUBLISH(TEST_NUM, test_entry); -val_api_t *val = NULL; -psa_api_t *psa = NULL; - -void test_entry(val_api_t *val_api, psa_api_t *psa_api) -{ - int32_t status = VAL_STATUS_SUCCESS; - - val = val_api; - psa = psa_api; - - /* test init */ - val->test_init(TEST_NUM, TEST_DESC, TEST_FIELD(TEST_ISOLATION_L1, WD_HIGH_TIMEOUT)); - if (!IS_TEST_START(val->get_status())) - { - goto test_exit; - } - - /* Execute list of tests available in test[num]_secure_storage_list from Non-secure side*/ - status = val->execute_non_secure_tests(TEST_NUM, test_s004_sst_list, FALSE); - - if (VAL_ERROR(status)) - { - goto test_exit; - } - -test_exit: - val->test_exit(); -} diff --git a/components/TARGET_PSA/TESTS/compliance_its/test_s004/test_its_data.h b/components/TARGET_PSA/TESTS/compliance_its/test_s004/test_its_data.h deleted file mode 100644 index b41dc1b..0000000 --- a/components/TARGET_PSA/TESTS/compliance_its/test_s004/test_its_data.h +++ /dev/null @@ -1,65 +0,0 @@ -/** @file - * Copyright (c) 2019, Arm Limited or its affiliates. All rights reserved. - * SPDX-License-Identifier : Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -**/ -#ifndef _TEST_S004_ITS_DATA_TESTS_H_ -#define _TEST_S004_ITS_DATA_TESTS_H_ - -#include "val_internal_trusted_storage.h" - -#define SST_FUNCTION val->its_function -#define psa_sst_uid_t psa_its_uid_t - -typedef struct { - enum its_function_code api; - psa_its_status_t status; -} test_data; - -static const test_data s004_data[] = { -{ - 0, 0 /* This is dummy for index0 */ -}, -{ - VAL_ITS_SET, PSA_ITS_SUCCESS /* Create a valid storage entity */ -}, -{ - VAL_ITS_GET, PSA_ITS_SUCCESS /* Validate the data using get API after set API failure */ -}, -{ - 0, 0 /* Index not used */ -}, -{ - VAL_ITS_SET, PSA_ITS_SUCCESS /* For same UID set the length as half of previous */ -}, -{ - VAL_ITS_GET, PSA_ITS_ERROR_INCORRECT_SIZE /* Call get with incorrect length */ -}, -{ - 0, 0 /* No data should be returned */ -}, -{ - VAL_ITS_GET, PSA_ITS_SUCCESS /* Call get API with correct length */ -}, -{ - 0, 0 /* No data should be returned */ -}, -{ - 0, 0 /* Check that we should not be able to access the old data */ -}, -{ - VAL_ITS_REMOVE, PSA_ITS_SUCCESS /* Remove the valid storage entity */ -}, -}; -#endif /* _TEST_S004_ITS_DATA_TESTS_H_ */ diff --git a/components/TARGET_PSA/TESTS/compliance_its/test_s004/test_ps_data.h b/components/TARGET_PSA/TESTS/compliance_its/test_s004/test_ps_data.h deleted file mode 100644 index baaf194..0000000 --- a/components/TARGET_PSA/TESTS/compliance_its/test_s004/test_ps_data.h +++ /dev/null @@ -1,65 +0,0 @@ -/** @file - * Copyright (c) 2019, Arm Limited or ps affiliates. All rights reserved. - * SPDX-License-Identifier : Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -**/ -#ifndef _TEST_S004_PS_DATA_TESTS_H_ -#define _TEST_S004_PS_DATA_TESTS_H_ - -#include "val_protected_storage.h" - -#define SST_FUNCTION val->ps_function -#define psa_sst_uid_t psa_ps_uid_t - -typedef struct { - enum ps_function_code api; - psa_ps_status_t status; -} test_data; - -static const test_data s004_data[] = { -{ - 0, 0 /* This is dummy for index0 */ -}, -{ - VAL_PS_SET, PSA_PS_SUCCESS /* Create a valid storage entity */ -}, -{ - VAL_PS_GET, PSA_PS_SUCCESS /* Validate the data using get API after set API failure */ -}, -{ - 0, 0 /* Index not used */ -}, -{ - VAL_PS_SET, PSA_PS_SUCCESS /* For same UID set the length as half of previous */ -}, -{ - VAL_PS_GET, PSA_PS_ERROR_INCORRECT_SIZE /* Call get with incorrect length */ -}, -{ - 0, 0 /* No data should be returned */ -}, -{ - VAL_PS_GET, PSA_PS_SUCCESS /* Call get API with correct length */ -}, -{ - 0, 0 /* No data should be returned */ -}, -{ - 0, 0 /* Check that we should not be able to access the old data */ -}, -{ - VAL_PS_REMOVE, PSA_PS_SUCCESS /* Remove the valid storage entity */ -}, -}; -#endif /* _TEST_S004_PS_DATA_TESTS_H_ */ diff --git a/components/TARGET_PSA/TESTS/compliance_its/test_s004/test_s004.c b/components/TARGET_PSA/TESTS/compliance_its/test_s004/test_s004.c deleted file mode 100644 index 004ee2f..0000000 --- a/components/TARGET_PSA/TESTS/compliance_its/test_s004/test_s004.c +++ /dev/null @@ -1,84 +0,0 @@ -/** @file - * Copyright (c) 2019, Arm Limited or its affiliates. All rights reserved. - * SPDX-License-Identifier : Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -**/ - -#include "val_interfaces.h" -#include "val_target.h" -#include "test_s004.h" -#ifdef ITS_TEST -#include "test_its_data.h" -#elif PS_TEST -#include "test_ps_data.h" -#endif - -#define TEST_BUFF_SIZE 20 - -client_test_t test_s004_sst_list[] = { - NULL, - psa_sst_get_data_check, - NULL, -}; - -static psa_sst_uid_t uid = UID_BASE_VALUE + 5; -static uint8_t read_buff[TEST_BUFF_SIZE] = {0}; -static uint8_t write_buff[TEST_BUFF_SIZE] = {0x99, 0x01, 0x30, 0x50, 0x04, 0x23, 0xF6, 0x07, 0x08, \ - 0x0D, 0x70, 0xA1, 0xFF, 0xFF, 0x14, 0x73, 0x46, 0x97, 0xE8, 0xDD}; - -int32_t psa_sst_get_data_check(caller_security_t caller) -{ - uint32_t status,j; - - /* Set data for UID */ - status = SST_FUNCTION(s004_data[1].api, uid, TEST_BUFF_SIZE, write_buff,0); - TEST_ASSERT_EQUAL(status, s004_data[1].status, TEST_CHECKPOINT_NUM(1)); - - /* Call get function and check the data consistency */ - status = SST_FUNCTION(s004_data[2].api, uid, 0, TEST_BUFF_SIZE, read_buff); - TEST_ASSERT_EQUAL(status, s004_data[2].status, TEST_CHECKPOINT_NUM(2)); - TEST_ASSERT_MEMCMP(read_buff, write_buff, TEST_BUFF_SIZE, TEST_CHECKPOINT_NUM(3)); - - /* Call the set again for same uid and set the length as half */ - status = SST_FUNCTION(s004_data[4].api, uid, TEST_BUFF_SIZE/2, write_buff, 0); - TEST_ASSERT_EQUAL(status, s004_data[4].status, TEST_CHECKPOINT_NUM(4)); - - /* Call get function with incorrect buffer length */ - val->print(PRINT_TEST, "[Check 1] Call get API with incorrect length\n", 0); - memset(read_buff, 0, TEST_BUFF_SIZE); - status = SST_FUNCTION(s004_data[5].api, uid, 0, TEST_BUFF_SIZE, read_buff); - TEST_ASSERT_EQUAL(status, s004_data[5].status, TEST_CHECKPOINT_NUM(5)); - for (j = 0; j < TEST_BUFF_SIZE; j++) - { - TEST_ASSERT_EQUAL(read_buff[j], 0, TEST_CHECKPOINT_NUM(6)); - } - - /* Call get function with CORRECT buffer length */ - status = SST_FUNCTION(s004_data[7].api, uid, 0, TEST_BUFF_SIZE/2, read_buff); - TEST_ASSERT_EQUAL(status, s004_data[7].status, TEST_CHECKPOINT_NUM(7)); - TEST_ASSERT_MEMCMP(read_buff, write_buff, TEST_BUFF_SIZE/2, TEST_CHECKPOINT_NUM(8)); - - /* Check we should not be able to access old set data */ - val->print(PRINT_TEST, "[Check 2] Old buffer invalid after length change\n", 0); - for (j = TEST_BUFF_SIZE/2; j < TEST_BUFF_SIZE; j++) - { - TEST_ASSERT_EQUAL(read_buff[j], 0, TEST_CHECKPOINT_NUM(9)); - } - - /* Remove the UID */ - status = SST_FUNCTION(s004_data[10].api, uid); - TEST_ASSERT_EQUAL(status, s004_data[10].status, TEST_CHECKPOINT_NUM(10)); - - return VAL_STATUS_SUCCESS; -} diff --git a/components/TARGET_PSA/TESTS/compliance_its/test_s004/test_s004.h b/components/TARGET_PSA/TESTS/compliance_its/test_s004/test_s004.h deleted file mode 100644 index 03c6ad1..0000000 --- a/components/TARGET_PSA/TESTS/compliance_its/test_s004/test_s004.h +++ /dev/null @@ -1,35 +0,0 @@ -/** @file - * Copyright (c) 2019, Arm Limited or its affiliates. All rights reserved. - * SPDX-License-Identifier : Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -**/ -#ifndef _TEST_S004_CLIENT_TESTS_H_ -#define _TEST_S004_CLIENT_TESTS_H_ - -#ifdef ITS_TEST -#define VAL_STORAGE_BASE VAL_INTERNAL_TRUSTED_STORAGE_BASE -#define test_entry CONCAT(test_entry_, s004) -#elif PS_TEST -#define VAL_STORAGE_BASE VAL_PROTECTED_STORAGE_BASE -#define test_entry CONCAT(test_entry_, p004) -#endif -#define val CONCAT(val,test_entry) -#define psa CONCAT(psa,test_entry) - -extern val_api_t *val; -extern psa_api_t *psa; -extern client_test_t test_s004_sst_list[]; - -int32_t psa_sst_get_data_check(caller_security_t caller); -#endif /* _TEST_S004_CLIENT_TESTS_H_ */ diff --git a/components/TARGET_PSA/TESTS/compliance_its/test_s005/main.c b/components/TARGET_PSA/TESTS/compliance_its/test_s005/main.c deleted file mode 100644 index b15f531..0000000 --- a/components/TARGET_PSA/TESTS/compliance_its/test_s005/main.c +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2020, Arm Limited and affiliates. - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include "val_interfaces.h" -#include "pal_mbed_os_intf.h" - -#if !defined(MBED_CONF_RTOS_PRESENT) -#error [NOT_SUPPORTED] PSA compliance its test cases require RTOS to run -#else - -#ifdef ITS_TEST -void test_entry_s005(val_api_t *val_api, psa_api_t *psa_api); -#elif PS_TEST -void test_entry_p005(val_api_t *val_api, psa_api_t *psa_api); -#endif - -int main(void) -{ -#ifdef ITS_TEST - test_start(test_entry_s005, COMPLIANCE_TEST_STORAGE); -#elif PS_TEST - test_start(test_entry_p005, COMPLIANCE_TEST_STORAGE); -#endif -} -#endif // !defined(MBED_CONF_RTOS_PRESENT) diff --git a/components/TARGET_PSA/TESTS/compliance_its/test_s005/test_entry.c b/components/TARGET_PSA/TESTS/compliance_its/test_s005/test_entry.c deleted file mode 100644 index 36dcbaa..0000000 --- a/components/TARGET_PSA/TESTS/compliance_its/test_s005/test_entry.c +++ /dev/null @@ -1,52 +0,0 @@ -/** @file - * Copyright (c) 2019, Arm Limited or its affiliates. All rights reserved. - * SPDX-License-Identifier : Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -**/ - -#include "val_interfaces.h" -#include "val_target.h" -#include "test_s005.h" - -#define TEST_NUM VAL_CREATE_TEST_ID(VAL_STORAGE_BASE, 5) -#define TEST_DESC "Success scenarios check\n" - -TEST_PUBLISH(TEST_NUM, test_entry); -val_api_t *val = NULL; -psa_api_t *psa = NULL; - -void test_entry(val_api_t *val_api, psa_api_t *psa_api) -{ - int32_t status = VAL_STATUS_SUCCESS; - - val = val_api; - psa = psa_api; - - /* test init */ - val->test_init(TEST_NUM, TEST_DESC, TEST_FIELD(TEST_ISOLATION_L1, WD_HIGH_TIMEOUT)); - if (!IS_TEST_START(val->get_status())) - { - goto test_exit; - } - - /* Execute list of tests available in test[num]_secure_storage_list from Non-secure side*/ - status = val->execute_non_secure_tests(TEST_NUM, test_s005_sst_list, FALSE); - if (VAL_ERROR(status)) - { - goto test_exit; - } - -test_exit: - val->test_exit(); -} diff --git a/components/TARGET_PSA/TESTS/compliance_its/test_s005/test_its_data.h b/components/TARGET_PSA/TESTS/compliance_its/test_s005/test_its_data.h deleted file mode 100644 index 653f7cc..0000000 --- a/components/TARGET_PSA/TESTS/compliance_its/test_s005/test_its_data.h +++ /dev/null @@ -1,58 +0,0 @@ -/** @file - * Copyright (c) 2019, Arm Limited or its affiliates. All rights reserved. - * SPDX-License-Identifier : Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -**/ -#ifndef _TEST_S005_ITS_DATA_TESTS_H_ -#define _TEST_S005_ITS_DATA_TESTS_H_ - -#include "val_internal_trusted_storage.h" - -#define SST_FUNCTION val->its_function -#define psa_sst_uid_t psa_its_uid_t -#define psa_sst_create_flags_t psa_its_create_flags_t - -typedef struct { - enum its_function_code api; - psa_its_status_t status; -} test_data; - -static struct psa_its_info_t info; -static const test_data s005_data[] = { -{ - 0, 0 /* This is dummy for index0 */ -}, -{ - VAL_ITS_SET, PSA_ITS_SUCCESS /* Create a valid storage entity */ -}, -{ - VAL_ITS_GET, PSA_ITS_SUCCESS /* Validate the data using get API */ -}, -{ - 0, 0 /* Index not used */ -}, -{ - VAL_ITS_GET_INFO, PSA_ITS_SUCCESS /* Validate the data attributes get_info API */ -}, -{ - 0, 0 /* Index not used */ -}, -{ - 0, 0 /* Index not used */ -}, -{ - VAL_ITS_REMOVE, PSA_ITS_SUCCESS /* Remove the valid storage entity */ -}, -}; -#endif /* _TEST_S005_ITS_DATA_TESTS_H_ */ diff --git a/components/TARGET_PSA/TESTS/compliance_its/test_s005/test_ps_data.h b/components/TARGET_PSA/TESTS/compliance_its/test_s005/test_ps_data.h deleted file mode 100644 index a961269..0000000 --- a/components/TARGET_PSA/TESTS/compliance_its/test_s005/test_ps_data.h +++ /dev/null @@ -1,58 +0,0 @@ -/** @file - * Copyright (c) 2019, Arm Limited or ps affiliates. All rights reserved. - * SPDX-License-Identifier : Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -**/ -#ifndef _TEST_S005_PS_DATA_TESTS_H_ -#define _TEST_S005_PS_DATA_TESTS_H_ - -#include "val_protected_storage.h" - -#define SST_FUNCTION val->ps_function -#define psa_sst_uid_t psa_ps_uid_t -#define psa_sst_create_flags_t psa_ps_create_flags_t - -typedef struct { - enum ps_function_code api; - psa_ps_status_t status; -} test_data; - -static struct psa_ps_info_t info; -static const test_data s005_data[] = { -{ - 0, 0 /* This is dummy for index0 */ -}, -{ - VAL_PS_SET, PSA_PS_SUCCESS /* Create a valid storage entity */ -}, -{ - VAL_PS_GET, PSA_PS_SUCCESS /* Validate the data using get API */ -}, -{ - 0, 0 /* Index not used */ -}, -{ - VAL_PS_GET_INFO, PSA_PS_SUCCESS /* Validate the data attributes get_info API */ -}, -{ - 0, 0 /* Index not used */ -}, -{ - 0, 0 /* Index not used */ -}, -{ - VAL_PS_REMOVE, PSA_PS_SUCCESS /* Remove the valid storage entity */ -}, -}; -#endif /* _TEST_S005_PS_DATA_TESTS_H_ */ diff --git a/components/TARGET_PSA/TESTS/compliance_its/test_s005/test_s005.c b/components/TARGET_PSA/TESTS/compliance_its/test_s005/test_s005.c deleted file mode 100644 index c974d04..0000000 --- a/components/TARGET_PSA/TESTS/compliance_its/test_s005/test_s005.c +++ /dev/null @@ -1,89 +0,0 @@ -/** @file - * Copyright (c) 2019, Arm Limited or its affiliates. All rights reserved. - * SPDX-License-Identifier : Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -**/ - -#include "val_interfaces.h" -#include "val_target.h" -#include "test_s005.h" -#ifdef ITS_TEST -#include "test_its_data.h" -#elif PS_TEST -#include "test_ps_data.h" -#endif - -#define TEST_BUFF_SIZE 30 - -client_test_t test_s005_sst_list[] = { - NULL, - psa_sst_apis_check_success_case, - NULL, -}; - -static uint8_t read_buff[TEST_BUFF_SIZE]; -static uint8_t write_buff[TEST_BUFF_SIZE] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x23, 0xF6, 0x07, 0x08, 0x0D, 0x0A, 0x1B, 0x0C, 0x5D, 0x0E,\ - 0x70, 0xA1, 0xFF, 0xFF, 0x14, 0x73, 0x46, 0x97, 0xE8, 0xDD, 0xCA, 0x0B, 0x3C, 0x0D, 0x2E}; - -static int32_t psa_sst_apis_check(psa_sst_uid_t uid, uint32_t data_len, - uint8_t *data_buff, psa_sst_create_flags_t create_flag) -{ - uint32_t status; - - /* Set the UID with the data_len and data_buff */ - status = SST_FUNCTION(s005_data[1].api, uid, data_len, data_buff, create_flag); - TEST_ASSERT_EQUAL(status, s005_data[1].status, TEST_CHECKPOINT_NUM(1)); - - /* Call the get function to get the data buffer and match the buffer */ - status = SST_FUNCTION(s005_data[2].api, uid, 0, data_len, read_buff); - TEST_ASSERT_EQUAL(status, s005_data[2].status, TEST_CHECKPOINT_NUM(2)); - TEST_ASSERT_MEMCMP(read_buff, data_buff, data_len, TEST_CHECKPOINT_NUM(3)); - - /* Call the get_info function and match the attributes */ - status = SST_FUNCTION(s005_data[4].api, uid, &info); - TEST_ASSERT_EQUAL(status, s005_data[4].status, TEST_CHECKPOINT_NUM(4)); - TEST_ASSERT_EQUAL(info.size, data_len, TEST_CHECKPOINT_NUM(5)); - TEST_ASSERT_EQUAL(info.flags, create_flag, TEST_CHECKPOINT_NUM(6)); - - /* Remove the UID */ - status = SST_FUNCTION(s005_data[7].api, uid); - TEST_ASSERT_EQUAL(status, s005_data[7].status, TEST_CHECKPOINT_NUM(7)); - - return VAL_STATUS_SUCCESS; -} - -int32_t psa_sst_apis_check_success_case(caller_security_t caller) -{ - psa_sst_uid_t uid = UID_BASE_VALUE + 4; - uint32_t data_len = 0, status = VAL_STATUS_SUCCESS; - - /* Calling set function with data_len 1 and valid data pointer */ - val->print(PRINT_TEST, "[Check 1] Set UID with data length zero and call storage APIs\n", 0); - if (psa_sst_apis_check(uid, data_len, write_buff, 0)) - { - val->print(PRINT_ERROR, "Data Len = %d\n", data_len); - return VAL_STATUS_ERROR; - } - - data_len = TEST_BUFF_SIZE/2; - val->print(PRINT_TEST, "[Check 2] Resetting the length check\n", 0); - if (psa_sst_apis_check(uid, data_len, write_buff, 0)) - { - val->print(PRINT_ERROR, "Data Len = %d\n", data_len); - return VAL_STATUS_ERROR; - } - - return status; -} diff --git a/components/TARGET_PSA/TESTS/compliance_its/test_s005/test_s005.h b/components/TARGET_PSA/TESTS/compliance_its/test_s005/test_s005.h deleted file mode 100644 index 9451737..0000000 --- a/components/TARGET_PSA/TESTS/compliance_its/test_s005/test_s005.h +++ /dev/null @@ -1,36 +0,0 @@ -/** @file - * Copyright (c) 2019, Arm Limited or its affiliates. All rights reserved. - * SPDX-License-Identifier : Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -**/ -#ifndef _TEST_S005_CLIENT_TESTS_H_ -#define _TEST_S005_CLIENT_TESTS_H_ - -#ifdef ITS_TEST -#define VAL_STORAGE_BASE VAL_INTERNAL_TRUSTED_STORAGE_BASE -#define test_entry CONCAT(test_entry_, s005) -#elif PS_TEST -#define VAL_STORAGE_BASE VAL_PROTECTED_STORAGE_BASE -#define test_entry CONCAT(test_entry_, p005) -#endif -#define val CONCAT(val,test_entry) -#define psa CONCAT(psa,test_entry) - -extern val_api_t *val; -extern psa_api_t *psa; -extern client_test_t test_s005_sst_list[]; - -int32_t psa_sst_apis_check_success_case(caller_security_t caller); - -#endif /* _TEST_S005_CLIENT_TESTS_H_ */ diff --git a/components/TARGET_PSA/TESTS/compliance_its/test_s006/main.c b/components/TARGET_PSA/TESTS/compliance_its/test_s006/main.c deleted file mode 100644 index 1a24de7..0000000 --- a/components/TARGET_PSA/TESTS/compliance_its/test_s006/main.c +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2020, Arm Limited and affiliates. - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include "val_interfaces.h" -#include "pal_mbed_os_intf.h" - -#if !defined(MBED_CONF_RTOS_PRESENT) -#error [NOT_SUPPORTED] PSA compliance its test cases require RTOS to run -#else - -#ifdef ITS_TEST -void test_entry_s006(val_api_t *val_api, psa_api_t *psa_api); -#elif PS_TEST -void test_entry_p006(val_api_t *val_api, psa_api_t *psa_api); -#endif - -int main(void) -{ -#ifdef ITS_TEST - test_start(test_entry_s006, COMPLIANCE_TEST_STORAGE); -#elif PS_TEST - test_start(test_entry_p006, COMPLIANCE_TEST_STORAGE); -#endif -} -#endif // !defined(MBED_CONF_RTOS_PRESENT) diff --git a/components/TARGET_PSA/TESTS/compliance_its/test_s006/test_entry.c b/components/TARGET_PSA/TESTS/compliance_its/test_s006/test_entry.c deleted file mode 100644 index dda491b..0000000 --- a/components/TARGET_PSA/TESTS/compliance_its/test_s006/test_entry.c +++ /dev/null @@ -1,52 +0,0 @@ -/** @file - * Copyright (c) 2019, Arm Limited or its affiliates. All rights reserved. - * SPDX-License-Identifier : Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -**/ - -#include "val_interfaces.h" -#include "val_target.h" -#include "test_s006.h" - -#define TEST_NUM VAL_CREATE_TEST_ID(VAL_STORAGE_BASE, 6) -#define TEST_DESC "Flags not supported check\n" - -TEST_PUBLISH(TEST_NUM, test_entry); -val_api_t *val = NULL; -psa_api_t *psa = NULL; - -void test_entry(val_api_t *val_api, psa_api_t *psa_api) -{ - int32_t status = VAL_STATUS_SUCCESS; - - val = val_api; - psa = psa_api; - - /* test init */ - val->test_init(TEST_NUM, TEST_DESC, TEST_FIELD(TEST_ISOLATION_L1, WD_HIGH_TIMEOUT)); - if (!IS_TEST_START(val->get_status())) - { - goto test_exit; - } - - /* Execute list of tests available in test[num]_secure_storage_list from Non-secure side*/ - status = val->execute_non_secure_tests(TEST_NUM, test_s006_sst_list, FALSE); - if (VAL_ERROR(status)) - { - goto test_exit; - } - -test_exit: - val->test_exit(); -} diff --git a/components/TARGET_PSA/TESTS/compliance_its/test_s006/test_its_data.h b/components/TARGET_PSA/TESTS/compliance_its/test_s006/test_its_data.h deleted file mode 100644 index 4426f2c..0000000 --- a/components/TARGET_PSA/TESTS/compliance_its/test_s006/test_its_data.h +++ /dev/null @@ -1,53 +0,0 @@ -/** @file - * Copyright (c) 2019, Arm Limited or its affiliates. All rights reserved. - * SPDX-License-Identifier : Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -**/ -#ifndef _TEST_S006_ITS_DATA_TESTS_H_ -#define _TEST_S006_ITS_DATA_TESTS_H_ - -#include "val_internal_trusted_storage.h" - -#define SST_FUNCTION val->its_function -#define PSA_SST_FLAG_WRITE_ONCE PSA_ITS_FLAG_WRITE_ONCE -#define psa_sst_uid_t psa_its_uid_t -#define psa_sst_create_flags_t psa_its_create_flags_t - -typedef struct { - enum its_function_code api; - psa_its_status_t status; -} test_data; - -static struct psa_its_info_t info; -static const test_data s006_data[] = { -{ - 0, PSA_ITS_ERROR_FLAGS_NOT_SUPPORTED /* This is dummy for index0 */ -}, -{ - VAL_ITS_SET, PSA_ITS_SUCCESS /* Create a valid storage entity with different flag values */ -}, -{ - VAL_ITS_GET_INFO, PSA_ITS_SUCCESS /* Validate the flag value get_info API */ -}, -{ - 0, 0 /* Index not used */ -}, -{ - VAL_ITS_REMOVE, PSA_ITS_SUCCESS /* Remove the storage entity */ -}, -{ - VAL_ITS_REMOVE, PSA_ITS_ERROR_UID_NOT_FOUND /* Storage entity remove fails */ -}, -}; -#endif /* _TEST_S006_ITS_DATA_TESTS_H_ */ diff --git a/components/TARGET_PSA/TESTS/compliance_its/test_s006/test_ps_data.h b/components/TARGET_PSA/TESTS/compliance_its/test_s006/test_ps_data.h deleted file mode 100644 index 86e1e30..0000000 --- a/components/TARGET_PSA/TESTS/compliance_its/test_s006/test_ps_data.h +++ /dev/null @@ -1,53 +0,0 @@ -/** @file - * Copyright (c) 2019, Arm Limited or ps affiliates. All rights reserved. - * SPDX-License-Identifier : Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -**/ -#ifndef _TEST_S006_PS_DATA_TESTS_H_ -#define _TEST_S006_PS_DATA_TESTS_H_ - -#include "val_protected_storage.h" - -#define SST_FUNCTION val->ps_function -#define PSA_SST_FLAG_WRITE_ONCE PSA_PS_FLAG_WRITE_ONCE -#define psa_sst_uid_t psa_ps_uid_t -#define psa_sst_create_flags_t psa_ps_create_flags_t - -typedef struct { - enum ps_function_code api; - psa_ps_status_t status; -} test_data; - -static struct psa_ps_info_t info; -static const test_data s006_data[] = { -{ - 0, PSA_PS_ERROR_FLAGS_NOT_SUPPORTED /* This is dummy for index0 */ -}, -{ - VAL_PS_SET, PSA_PS_SUCCESS /* Create a valid storage entity with different flag values */ -}, -{ - VAL_PS_GET_INFO, PSA_PS_SUCCESS /* Validate the flag value get_info API */ -}, -{ - 0, 0 /* Index not used */ -}, -{ - VAL_PS_REMOVE, PSA_PS_SUCCESS /* Remove the storage entity */ -}, -{ - VAL_PS_REMOVE, PSA_PS_ERROR_UID_NOT_FOUND /* Remove the storage entity */ -} -}; -#endif /* _TEST_S006_PS_DATA_TESTS_H_ */ diff --git a/components/TARGET_PSA/TESTS/compliance_its/test_s006/test_s006.c b/components/TARGET_PSA/TESTS/compliance_its/test_s006/test_s006.c deleted file mode 100644 index 26b8984..0000000 --- a/components/TARGET_PSA/TESTS/compliance_its/test_s006/test_s006.c +++ /dev/null @@ -1,90 +0,0 @@ -/** @file - * Copyright (c) 2019, Arm Limited or its affiliates. All rights reserved. - * SPDX-License-Identifier : Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -**/ - -#include "val_interfaces.h" -#include "val_target.h" -#include "test_s006.h" -#ifdef ITS_TEST -#include "test_its_data.h" -#elif PS_TEST -#include "test_ps_data.h" -#endif - -#define TEST_BUFF_SIZE 30 - -client_test_t test_s006_sst_list[] = { - NULL, - psa_sst_flags_not_supported, - NULL, -}; - -static uint8_t write_buff[TEST_BUFF_SIZE] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x23, 0xF6, 0x07, 0x08, 0x0D, 0x0A, 0x1B, 0x0C, 0x5D, 0x0E,\ - 0x70, 0xA1, 0xFF, 0xFF, 0x14, 0x73, 0x46, 0x97, 0xE8, 0xDD, 0xCA, 0x0B, 0x3C, 0x0D, 0x2E}; - -static int32_t psa_sst_remove_api(psa_sst_uid_t uid, uint32_t data_len, - uint8_t *data_buff, psa_sst_create_flags_t create_flag) -{ - uint32_t status; - - /* Call the get_info function and match the attributes */ - status = SST_FUNCTION(s006_data[2].api, uid, &info); - TEST_ASSERT_EQUAL(status, s006_data[2].status, TEST_CHECKPOINT_NUM(2)); - TEST_ASSERT_EQUAL(info.flags, create_flag, TEST_CHECKPOINT_NUM(3)); - - /* Remove the UID */ - status = SST_FUNCTION(s006_data[4].api, uid); - TEST_ASSERT_EQUAL(status, s006_data[4].status, TEST_CHECKPOINT_NUM(4)); - - return VAL_STATUS_SUCCESS; -} - -int32_t psa_sst_flags_not_supported(caller_security_t caller) -{ - psa_sst_create_flags_t flag = 0x80000000; - uint32_t status = VAL_STATUS_SUCCESS; - psa_sst_uid_t uid = UID_BASE_VALUE + 5; - int32_t test_status; - - /* Calling set function with different create flag value */ - - val->print(PRINT_TEST, "[Check 1] Call set API with valid flag values\n", 0); - while (flag) - { - /* Create storage with flag value */ - status = SST_FUNCTION(s006_data[1].api, uid, TEST_BUFF_SIZE, write_buff, - (flag & (~PSA_SST_FLAG_WRITE_ONCE))); - - if (status == s006_data[1].status) - { - test_status = psa_sst_remove_api(uid, TEST_BUFF_SIZE, write_buff, - (flag & (~PSA_SST_FLAG_WRITE_ONCE))); - if (test_status != VAL_STATUS_SUCCESS) - return test_status; - } - else if (status == s006_data[0].status) - { - /* Remove UID should fail */ - status = SST_FUNCTION(s006_data[5].api, uid); - TEST_ASSERT_EQUAL(status, s006_data[5].status, TEST_CHECKPOINT_NUM(5)); - } - - flag = flag >> 1; - }; - - return status; -} diff --git a/components/TARGET_PSA/TESTS/compliance_its/test_s006/test_s006.h b/components/TARGET_PSA/TESTS/compliance_its/test_s006/test_s006.h deleted file mode 100644 index 9e79324..0000000 --- a/components/TARGET_PSA/TESTS/compliance_its/test_s006/test_s006.h +++ /dev/null @@ -1,36 +0,0 @@ -/** @file - * Copyright (c) 2019, Arm Limited or its affiliates. All rights reserved. - * SPDX-License-Identifier : Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -**/ -#ifndef _TEST_S006_CLIENT_TESTS_H_ -#define _TEST_S006_CLIENT_TESTS_H_ - -#ifdef ITS_TEST -#define VAL_STORAGE_BASE VAL_INTERNAL_TRUSTED_STORAGE_BASE -#define test_entry CONCAT(test_entry_, s006) -#elif PS_TEST -#define VAL_STORAGE_BASE VAL_PROTECTED_STORAGE_BASE -#define test_entry CONCAT(test_entry_, p006) -#endif -#define val CONCAT(val,test_entry) -#define psa CONCAT(psa,test_entry) - -extern val_api_t *val; -extern psa_api_t *psa; -extern client_test_t test_s006_sst_list[]; - -int32_t psa_sst_flags_not_supported(caller_security_t caller); - -#endif /* _TEST_S006_CLIENT_TESTS_H_ */ diff --git a/components/TARGET_PSA/TESTS/compliance_its/test_s007/main.c b/components/TARGET_PSA/TESTS/compliance_its/test_s007/main.c deleted file mode 100644 index a63001e..0000000 --- a/components/TARGET_PSA/TESTS/compliance_its/test_s007/main.c +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2020, Arm Limited and affiliates. - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include "val_interfaces.h" -#include "pal_mbed_os_intf.h" - -#if !defined(MBED_CONF_RTOS_PRESENT) -#error [NOT_SUPPORTED] PSA compliance its test cases require RTOS to run -#else - -#ifdef ITS_TEST -void test_entry_s007(val_api_t *val_api, psa_api_t *psa_api); -#elif PS_TEST -void test_entry_p007(val_api_t *val_api, psa_api_t *psa_api); -#endif - -int main(void) -{ -#ifdef ITS_TEST - test_start(test_entry_s007, COMPLIANCE_TEST_STORAGE); -#elif PS_TEST - test_start(test_entry_p007, COMPLIANCE_TEST_STORAGE); -#endif -} -#endif // !defined(MBED_CONF_RTOS_PRESENT) diff --git a/components/TARGET_PSA/TESTS/compliance_its/test_s007/test_entry.c b/components/TARGET_PSA/TESTS/compliance_its/test_s007/test_entry.c deleted file mode 100644 index f6005a1..0000000 --- a/components/TARGET_PSA/TESTS/compliance_its/test_s007/test_entry.c +++ /dev/null @@ -1,52 +0,0 @@ -/** @file - * Copyright (c) 2019, Arm Limited or its affiliates. All rights reserved. - * SPDX-License-Identifier : Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -**/ - -#include "val_interfaces.h" -#include "val_target.h" -#include "test_s007.h" - -#define TEST_NUM VAL_CREATE_TEST_ID(VAL_STORAGE_BASE, 7) -#define TEST_DESC "Incorrect Size check\n" - -TEST_PUBLISH(TEST_NUM, test_entry); -val_api_t *val = NULL; -psa_api_t *psa = NULL; - -void test_entry(val_api_t *val_api, psa_api_t *psa_api) -{ - int32_t status = VAL_STATUS_SUCCESS; - - val = val_api; - psa = psa_api; - - /* test init */ - val->test_init(TEST_NUM, TEST_DESC, TEST_FIELD(TEST_ISOLATION_L1, WD_HIGH_TIMEOUT)); - if (!IS_TEST_START(val->get_status())) - { - goto test_exit; - } - - /* Execute list of tests available in test[num]_secure_storage_list from Non-secure side*/ - status = val->execute_non_secure_tests(TEST_NUM, test_s007_sst_list, FALSE); - if (VAL_ERROR(status)) - { - goto test_exit; - } - -test_exit: - val->test_exit(); -} diff --git a/components/TARGET_PSA/TESTS/compliance_its/test_s007/test_its_data.h b/components/TARGET_PSA/TESTS/compliance_its/test_s007/test_its_data.h deleted file mode 100644 index 550dffb..0000000 --- a/components/TARGET_PSA/TESTS/compliance_its/test_s007/test_its_data.h +++ /dev/null @@ -1,65 +0,0 @@ -/** @file - * Copyright (c) 2019, Arm Limited or its affiliates. All rights reserved. - * SPDX-License-Identifier : Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -**/ -#ifndef _TEST_S007_ITS_DATA_TESTS_H_ -#define _TEST_S007_ITS_DATA_TESTS_H_ - -#include "val_internal_trusted_storage.h" - -#define SST_FUNCTION val->its_function -#define psa_sst_uid_t psa_its_uid_t - -typedef struct { - enum its_function_code api; - psa_its_status_t status; -} test_data; - -static const test_data s007_data[] = { -{ - 0, 0 /* This is dummy for index0 */ -}, -{ - VAL_ITS_SET, PSA_ITS_SUCCESS /* Create a valid storage entity */ -}, -{ - VAL_ITS_SET, PSA_ITS_SUCCESS /* Increase the length of storage */ -}, -{ - VAL_ITS_GET, PSA_ITS_SUCCESS /* Try to access old length */ -}, -{ - VAL_ITS_GET, PSA_ITS_SUCCESS /* Try to access valid length less than set length */ -}, -{ - 0, 0 /* This is dummy for index5 */ -}, -{ - VAL_ITS_SET, PSA_ITS_SUCCESS /* Decrease the length of storage */ -}, -{ - VAL_ITS_GET, PSA_ITS_ERROR_INCORRECT_SIZE /* Try to access old length */ -}, -{ - VAL_ITS_GET, PSA_ITS_ERROR_INCORRECT_SIZE /* Try to access old length */ -}, -{ - VAL_ITS_GET, PSA_ITS_SUCCESS /* Try to access data with correct length */ -}, -{ - VAL_ITS_REMOVE, PSA_ITS_SUCCESS /* Remove the storage entity */ -}, -}; -#endif /* _TEST_S007_ITS_DATA_TESTS_H_ */ diff --git a/components/TARGET_PSA/TESTS/compliance_its/test_s007/test_ps_data.h b/components/TARGET_PSA/TESTS/compliance_its/test_s007/test_ps_data.h deleted file mode 100644 index fa032c1..0000000 --- a/components/TARGET_PSA/TESTS/compliance_its/test_s007/test_ps_data.h +++ /dev/null @@ -1,65 +0,0 @@ -/** @file - * Copyright (c) 2019, Arm Limited or ps affiliates. All rights reserved. - * SPDX-License-Identifier : Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -**/ -#ifndef _TEST_S007_PS_DATA_TESTS_H_ -#define _TEST_S007_PS_DATA_TESTS_H_ - -#include "val_protected_storage.h" - -#define SST_FUNCTION val->ps_function -#define psa_sst_uid_t psa_ps_uid_t - -typedef struct { - enum ps_function_code api; - psa_ps_status_t status; -} test_data; - -static const test_data s007_data[] = { -{ - 0, 0 /* This is dummy for index0 */ -}, -{ - VAL_PS_SET, PSA_PS_SUCCESS /* Create a valid storage entity */ -}, -{ - VAL_PS_SET, PSA_PS_SUCCESS /* Increase the length of storage */ -}, -{ - VAL_PS_GET, PSA_PS_SUCCESS /* Try to access old length */ -}, -{ - VAL_PS_GET, PSA_PS_SUCCESS /* Try to access valid length less than set length */ -}, -{ - 0, 0 /* This is dummy for index5 */ -}, -{ - VAL_PS_SET, PSA_PS_SUCCESS /* Decrease the length of storage */ -}, -{ - VAL_PS_GET, PSA_PS_ERROR_INCORRECT_SIZE /* Try to access old length */ -}, -{ - VAL_PS_GET, PSA_PS_ERROR_INCORRECT_SIZE /* Try to access old length */ -}, -{ - VAL_PS_GET, PSA_PS_SUCCESS /* Try to access data with correct length */ -}, -{ - VAL_PS_REMOVE, PSA_PS_SUCCESS /* Remove the storage entity */ -}, -}; -#endif /* _TEST_S007_PS_DATA_TESTS_H_ */ diff --git a/components/TARGET_PSA/TESTS/compliance_its/test_s007/test_s007.c b/components/TARGET_PSA/TESTS/compliance_its/test_s007/test_s007.c deleted file mode 100644 index b17143c..0000000 --- a/components/TARGET_PSA/TESTS/compliance_its/test_s007/test_s007.c +++ /dev/null @@ -1,89 +0,0 @@ -/** @file - * Copyright (c) 2019, Arm Limited or its affiliates. All rights reserved. - * SPDX-License-Identifier : Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -**/ - -#include "val_interfaces.h" -#include "val_target.h" -#include "test_s007.h" -#ifdef ITS_TEST -#include "test_its_data.h" -#elif PS_TEST -#include "test_ps_data.h" -#endif - -#define TEST_BUFF_SIZE 30 - -client_test_t test_s007_sst_list[] = { - NULL, - psa_sst_get_incorrect_size, - NULL, -}; - -static uint8_t write_buff[TEST_BUFF_SIZE] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x23, 0xF6, 0x07, 0x08, 0x0D, 0x0A, 0x1B, 0x0C, 0x5D, 0x0E,\ - 0x70, 0xA1, 0xFF, 0xFF, 0x14, 0x73, 0x46, 0x97, 0xE8, 0xDD, 0xCA, 0x0B, 0x3C, 0x0D, 0x2E}; -static uint8_t read_buff[TEST_BUFF_SIZE]; - -int32_t psa_sst_get_incorrect_size(caller_security_t caller) -{ - psa_sst_uid_t uid = UID_BASE_VALUE + 5; - uint32_t status = VAL_STATUS_SUCCESS; - - /* Set the UID with the data_len and data_buff */ - val->print(PRINT_TEST, "Create a valid Storage\n", 0); - status = SST_FUNCTION(s007_data[1].api, uid, TEST_BUFF_SIZE/2, write_buff, 0); - TEST_ASSERT_EQUAL(status, s007_data[1].status, TEST_CHECKPOINT_NUM(1)); - - /* Call set for same UID and increase the length */ - val->print(PRINT_TEST, "Increase the length of storage\n", 0); - status = SST_FUNCTION(s007_data[2].api, uid, TEST_BUFF_SIZE, write_buff, 0); - TEST_ASSERT_EQUAL(status, s007_data[2].status, TEST_CHECKPOINT_NUM(2)); - - /* Access data using get API and old length */ - val->print(PRINT_TEST, "[Check 1] Call get API with old length\n", 0); - status = SST_FUNCTION(s007_data[3].api, uid, 0, TEST_BUFF_SIZE/2, read_buff); - TEST_ASSERT_EQUAL(status, s007_data[3].status, TEST_CHECKPOINT_NUM(3)); - - /* Access data using get API and valid length */ - status = SST_FUNCTION(s007_data[4].api, uid, 0, TEST_BUFF_SIZE/4, read_buff); - TEST_ASSERT_EQUAL(status, s007_data[4].status, TEST_CHECKPOINT_NUM(4)); - TEST_ASSERT_MEMCMP(read_buff, write_buff, TEST_BUFF_SIZE/4, TEST_CHECKPOINT_NUM(5)); - - /* Decrease the length again */ - val->print(PRINT_TEST, "Decrease the length of storage\n", 0); - status = SST_FUNCTION(s007_data[6].api, uid, TEST_BUFF_SIZE/4, write_buff, 0); - TEST_ASSERT_EQUAL(status, s007_data[6].status, TEST_CHECKPOINT_NUM(6)); - - /* Access data using get API and old length */ - status = SST_FUNCTION(s007_data[7].api, uid, 0, TEST_BUFF_SIZE/2, read_buff); - TEST_ASSERT_EQUAL(status, s007_data[7].status, TEST_CHECKPOINT_NUM(7)); - - /* Access data using get API and old length */ - val->print(PRINT_TEST, "[Check 2] Call get API with old length\n", 0); - status = SST_FUNCTION(s007_data[8].api, uid, 0, TEST_BUFF_SIZE, read_buff); - TEST_ASSERT_EQUAL(status, s007_data[8].status, TEST_CHECKPOINT_NUM(8)); - - /* Access data using correct length */ - val->print(PRINT_TEST, "[Check 3] Call get API with valid length\n", 0); - status = SST_FUNCTION(s007_data[9].api, uid, 0, TEST_BUFF_SIZE/4, read_buff); - TEST_ASSERT_EQUAL(status, s007_data[9].status, TEST_CHECKPOINT_NUM(9)); - - /* Remove the UID */ - status = SST_FUNCTION(s007_data[10].api, uid); - TEST_ASSERT_EQUAL(status, s007_data[10].status, TEST_CHECKPOINT_NUM(10)); - - return status; -} diff --git a/components/TARGET_PSA/TESTS/compliance_its/test_s007/test_s007.h b/components/TARGET_PSA/TESTS/compliance_its/test_s007/test_s007.h deleted file mode 100644 index b663980..0000000 --- a/components/TARGET_PSA/TESTS/compliance_its/test_s007/test_s007.h +++ /dev/null @@ -1,36 +0,0 @@ -/** @file - * Copyright (c) 2019, Arm Limited or its affiliates. All rights reserved. - * SPDX-License-Identifier : Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -**/ -#ifndef _TEST_S007_CLIENT_TESTS_H_ -#define _TEST_S007_CLIENT_TESTS_H_ - -#ifdef ITS_TEST -#define VAL_STORAGE_BASE VAL_INTERNAL_TRUSTED_STORAGE_BASE -#define test_entry CONCAT(test_entry_, s007) -#elif PS_TEST -#define VAL_STORAGE_BASE VAL_PROTECTED_STORAGE_BASE -#define test_entry CONCAT(test_entry_, p007) -#endif -#define val CONCAT(val,test_entry) -#define psa CONCAT(psa,test_entry) - -extern val_api_t *val; -extern psa_api_t *psa; -extern client_test_t test_s007_sst_list[]; - -int32_t psa_sst_get_incorrect_size(caller_security_t caller); - -#endif /* _TEST_S007_CLIENT_TESTS_H_ */ diff --git a/components/TARGET_PSA/TESTS/compliance_its/test_s008/main.c b/components/TARGET_PSA/TESTS/compliance_its/test_s008/main.c deleted file mode 100644 index b17f6cf..0000000 --- a/components/TARGET_PSA/TESTS/compliance_its/test_s008/main.c +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2020, Arm Limited and affiliates. - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include "val_interfaces.h" -#include "pal_mbed_os_intf.h" - -#if !defined(MBED_CONF_RTOS_PRESENT) -#error [NOT_SUPPORTED] PSA compliance its test cases require RTOS to run -#else - -#ifdef ITS_TEST -void test_entry_s008(val_api_t *val_api, psa_api_t *psa_api); -#elif PS_TEST -void test_entry_p008(val_api_t *val_api, psa_api_t *psa_api); -#endif - -int main(void) -{ -#ifdef ITS_TEST - test_start(test_entry_s008, COMPLIANCE_TEST_STORAGE); -#elif PS_TEST - test_start(test_entry_p008, COMPLIANCE_TEST_STORAGE); -#endif -} -#endif // !defined(MBED_CONF_RTOS_PRESENT) diff --git a/components/TARGET_PSA/TESTS/compliance_its/test_s008/test_entry.c b/components/TARGET_PSA/TESTS/compliance_its/test_s008/test_entry.c deleted file mode 100644 index f531881..0000000 --- a/components/TARGET_PSA/TESTS/compliance_its/test_s008/test_entry.c +++ /dev/null @@ -1,53 +0,0 @@ -/** @file - * Copyright (c) 2019, Arm Limited or its affiliates. All rights reserved. - * SPDX-License-Identifier : Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -**/ - -#include "val_interfaces.h" -#include "val_target.h" -#include "test_s008.h" - -#define TEST_NUM VAL_CREATE_TEST_ID(VAL_STORAGE_BASE, 8) -#define TEST_DESC "Invalid offset check\n" - -TEST_PUBLISH(TEST_NUM, test_entry); -val_api_t *val = NULL; -psa_api_t *psa = NULL; - -void test_entry(val_api_t *val_api, psa_api_t *psa_api) -{ - int32_t status = VAL_STATUS_SUCCESS; - - val = val_api; - psa = psa_api; - - /* test init */ - val->test_init(TEST_NUM, TEST_DESC, TEST_FIELD(TEST_ISOLATION_L1, WD_HIGH_TIMEOUT)); - if (!IS_TEST_START(val->get_status())) - { - goto test_exit; - } - - /* Execute list of tests available in test[num]_secure_storage_list from Non-secure side*/ - status = val->execute_non_secure_tests(TEST_NUM, test_s008_sst_list, FALSE); - - if (VAL_ERROR(status)) - { - goto test_exit; - } - -test_exit: - val->test_exit(); -} diff --git a/components/TARGET_PSA/TESTS/compliance_its/test_s008/test_its_data.h b/components/TARGET_PSA/TESTS/compliance_its/test_s008/test_its_data.h deleted file mode 100644 index 89093d4..0000000 --- a/components/TARGET_PSA/TESTS/compliance_its/test_s008/test_its_data.h +++ /dev/null @@ -1,74 +0,0 @@ -/** @file - * Copyright (c) 2019, Arm Limited or its affiliates. All rights reserved. - * SPDX-License-Identifier : Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -**/ -#ifndef _TEST_S008_ITS_DATA_TESTS_H_ -#define _TEST_S008_ITS_DATA_TESTS_H_ - -#include "val_internal_trusted_storage.h" - -#define SST_FUNCTION val->its_function -#define psa_sst_uid_t psa_its_uid_t - -typedef struct { - enum its_function_code api; - psa_its_status_t status; -} test_data; - -static const test_data s008_data[] = { -{ - 0, 0 /* This is dummy for index0 */ -}, -{ - VAL_ITS_SET, PSA_ITS_SUCCESS /* Create a valid storage entity with zero flag value */ -}, -{ - VAL_ITS_GET, PSA_ITS_SUCCESS /* Call get API with offset + data_len = total_size */ -}, -{ - 0, 0 /* This is dummy for index3 */ -}, -{ - VAL_ITS_GET, PSA_ITS_SUCCESS /* Call get API with offset + data_len < total_size */ -}, -{ - 0, 0 /* This is dummy for index5 */ -}, -{ - VAL_ITS_GET, PSA_ITS_SUCCESS /* Call get API with offset = total data_size + 1 */ -}, -{ - 0, 0 /* This is dummy for index7 */ -}, -{ - VAL_ITS_GET, PSA_ITS_ERROR_INCORRECT_SIZE /* get API with offset + data_len > total data_size */ -}, -{ - 0, 0 /* This is dummy for index9 */ -}, -{ - VAL_ITS_GET, PSA_ITS_ERROR_INCORRECT_SIZE /* Call get API with invalid data len and offset zero */ -}, -{ - 0, 0 /* This is dummy for index11 */ -}, -{ - VAL_ITS_GET, PSA_ITS_SUCCESS /* Call get API with offset = MAX_UINT32 */ -}, -{ - VAL_ITS_REMOVE, PSA_ITS_SUCCESS /* Remove the storage entity */ -}, -}; -#endif /* _TEST_S008_ITS_DATA_TESTS_H_ */ diff --git a/components/TARGET_PSA/TESTS/compliance_its/test_s008/test_ps_data.h b/components/TARGET_PSA/TESTS/compliance_its/test_s008/test_ps_data.h deleted file mode 100644 index 2b15d35..0000000 --- a/components/TARGET_PSA/TESTS/compliance_its/test_s008/test_ps_data.h +++ /dev/null @@ -1,74 +0,0 @@ -/** @file - * Copyright (c) 2019, Arm Limited or ps affiliates. All rights reserved. - * SPDX-License-Identifier : Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -**/ -#ifndef _TEST_S008_PS_DATA_TESTS_H_ -#define _TEST_S008_PS_DATA_TESTS_H_ - -#include "val_protected_storage.h" - -#define SST_FUNCTION val->ps_function -#define psa_sst_uid_t psa_ps_uid_t - -typedef struct { - enum ps_function_code api; - psa_ps_status_t status; -} test_data; - -static const test_data s008_data[] = { -{ - 0, 0 /* This is dummy for index0 */ -}, -{ - VAL_PS_SET, PSA_PS_SUCCESS /* Create a valid storage entity with zero flag value */ -}, -{ - VAL_PS_GET, PSA_PS_SUCCESS /* Call get API with offset + data_len = total_size */ -}, -{ - 0, 0 /* This is dummy for index3 */ -}, -{ - VAL_PS_GET, PSA_PS_SUCCESS /* Call get API with offset + data_len < total_size */ -}, -{ - 0, 0 /* This is dummy for index5 */ -}, -{ - VAL_PS_GET, PSA_PS_SUCCESS/* Call get API with offset = total data_size + 1 */ -}, -{ - 0, 0 /* This is dummy for index7 */ -}, -{ - VAL_PS_GET, PSA_PS_ERROR_INCORRECT_SIZE /* Call get API with offset + data_len > total data_size */ -}, -{ - 0, 0 /* This is dummy for index9 */ -}, -{ - VAL_PS_GET, PSA_PS_ERROR_INCORRECT_SIZE /* Call get API with invalid data len and offset zero */ -}, -{ - 0, 0 /* This is dummy for index11 */ -}, -{ - VAL_PS_GET, PSA_PS_SUCCESS /* Call get API with offset = MAX_UINT32 */ -}, -{ - VAL_PS_REMOVE, PSA_PS_SUCCESS /* Remove the storage entity */ -}, -}; -#endif /* _TEST_S008_PS_DATA_TESTS_H_ */ diff --git a/components/TARGET_PSA/TESTS/compliance_its/test_s008/test_s008.c b/components/TARGET_PSA/TESTS/compliance_its/test_s008/test_s008.c deleted file mode 100644 index 7a2536e..0000000 --- a/components/TARGET_PSA/TESTS/compliance_its/test_s008/test_s008.c +++ /dev/null @@ -1,116 +0,0 @@ -/** @file - * Copyright (c) 2019, Arm Limited or its affiliates. All rights reserved. - * SPDX-License-Identifier : Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -**/ - -#include "val_interfaces.h" -#include "val_target.h" -#include "test_s008.h" -#ifdef ITS_TEST -#include "test_its_data.h" -#elif PS_TEST -#include "test_ps_data.h" -#endif - -#define TEST_BUFF_SIZE 20 -#define TEST_MAX_UINT32 0xFFFFFFFF - -client_test_t test_s008_sst_list[] = { - NULL, - psa_sst_valid_offset_success, - psa_sst_invalid_offset_failure, - NULL, -}; - -static psa_sst_uid_t uid = UID_BASE_VALUE + 5; -static uint8_t read_buff[TEST_BUFF_SIZE]; -static uint8_t write_buff[TEST_BUFF_SIZE] = {0x99, 0x01, 0x02, 0x03, 0x04, 0x23, 0xF6, 0x07, 0x08, \ - 0x0D, 0x70, 0xA1, 0xFF, 0xFF, 0x14, 0x73, 0x46, 0x97, 0xE8, 0xDD}; - -int32_t psa_sst_invalid_offset_failure(caller_security_t caller) -{ - uint32_t status, j; - - /* Case where offset = data_size +1 , data_len 0. Also check nothing is returned in read buff*/ - val->print(PRINT_TEST, "[Check 2] Try to access data with varying invalid offset\n", 0); - memset(read_buff, 0, TEST_BUFF_SIZE); - status = SST_FUNCTION(s008_data[6].api, uid, TEST_BUFF_SIZE+1, 0, read_buff); - TEST_ASSERT_NOT_EQUAL(status, s008_data[6].status, TEST_CHECKPOINT_NUM(6)); - for (j = 0; j < TEST_BUFF_SIZE; j++) - { - TEST_ASSERT_EQUAL(read_buff[j], 0x00, TEST_CHECKPOINT_NUM(7)); - } - - /* Case where offset = data_size , data_len= 1 Also check nothing is returned in read buff*/ - status = SST_FUNCTION(s008_data[8].api, uid, TEST_BUFF_SIZE, 1, read_buff); - TEST_ASSERT_EQUAL(status, s008_data[8].status, TEST_CHECKPOINT_NUM(8)); - for (j = 0; j < TEST_BUFF_SIZE; j++) - { - TEST_ASSERT_EQUAL(read_buff[j], 0x00, TEST_CHECKPOINT_NUM(9)); - } - - /* Case where offset = 0 , data_len > data_size Also check nothing is returned in read buff*/ - status = SST_FUNCTION(s008_data[10].api, uid, 0, TEST_BUFF_SIZE+1, read_buff); - TEST_ASSERT_EQUAL(status, s008_data[10].status, TEST_CHECKPOINT_NUM(10)); - for (j = 0; j < TEST_BUFF_SIZE; j++) - { - TEST_ASSERT_EQUAL(read_buff[j], 0x00, TEST_CHECKPOINT_NUM(11)); - } - - /* Try to access data with offset as MAX_UINT32 and length less than buffer size */ - status = SST_FUNCTION(s008_data[12].api, uid, TEST_MAX_UINT32, TEST_BUFF_SIZE/2, read_buff); - TEST_ASSERT_NOT_EQUAL(status, s008_data[12].status, TEST_CHECKPOINT_NUM(12)); - - /* Remove the UID */ - status = SST_FUNCTION(s008_data[13].api, uid); - TEST_ASSERT_EQUAL(status, s008_data[13].status, TEST_CHECKPOINT_NUM(13)); - - return VAL_STATUS_SUCCESS; -} - -int32_t psa_sst_valid_offset_success(caller_security_t caller) -{ - uint32_t status, data_len, offset = TEST_BUFF_SIZE; - - /* Set data for UID */ - status = SST_FUNCTION(s008_data[1].api, uid, TEST_BUFF_SIZE, write_buff, 0); - TEST_ASSERT_EQUAL(status, s008_data[1].status, TEST_CHECKPOINT_NUM(1)); - - /* Case where offset + datalen = data_size */ - val->print(PRINT_TEST, "[Check 1] Try to access data with varying valid offset\n", 0); - while (offset > 0) - { - data_len = TEST_BUFF_SIZE - offset; - memset(read_buff, 0, TEST_BUFF_SIZE); - status = SST_FUNCTION(s008_data[2].api, uid, offset, data_len, read_buff); - TEST_ASSERT_EQUAL(status, s008_data[2].status, TEST_CHECKPOINT_NUM(2)); - TEST_ASSERT_MEMCMP(read_buff, write_buff + offset, data_len, TEST_CHECKPOINT_NUM(3)); - offset >>= 1; - } - - offset = TEST_BUFF_SIZE - 2; - data_len = 1; - /* Case where offset + datalen < data_size */ - while (offset > 0) - { - status = SST_FUNCTION(s008_data[4].api, uid, offset, data_len, read_buff); - TEST_ASSERT_EQUAL(status, s008_data[4].status, TEST_CHECKPOINT_NUM(4)); - TEST_ASSERT_MEMCMP(read_buff, write_buff + offset, data_len, TEST_CHECKPOINT_NUM(5)); - offset >>= 1; - data_len <<= 1; - } - - return VAL_STATUS_SUCCESS; -} diff --git a/components/TARGET_PSA/TESTS/compliance_its/test_s008/test_s008.h b/components/TARGET_PSA/TESTS/compliance_its/test_s008/test_s008.h deleted file mode 100644 index d036b4a..0000000 --- a/components/TARGET_PSA/TESTS/compliance_its/test_s008/test_s008.h +++ /dev/null @@ -1,37 +0,0 @@ -/** @file - * Copyright (c) 2019, Arm Limited or its affiliates. All rights reserved. - * SPDX-License-Identifier : Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -**/ -#ifndef _TEST_S008_CLIENT_TESTS_H_ -#define _TEST_S008_CLIENT_TESTS_H_ - -#ifdef ITS_TEST -#define VAL_STORAGE_BASE VAL_INTERNAL_TRUSTED_STORAGE_BASE -#define test_entry CONCAT(test_entry_, s008) -#elif PS_TEST -#define VAL_STORAGE_BASE VAL_PROTECTED_STORAGE_BASE -#define test_entry CONCAT(test_entry_, p008) -#endif -#define val CONCAT(val,test_entry) -#define psa CONCAT(psa,test_entry) - -extern val_api_t *val; -extern psa_api_t *psa; -extern client_test_t test_s008_sst_list[]; - -int32_t psa_sst_valid_offset_success(caller_security_t caller); -int32_t psa_sst_invalid_offset_failure(caller_security_t caller); - -#endif /* _TEST_S008_CLIENT_TESTS_H_ */ diff --git a/components/TARGET_PSA/TESTS/compliance_its/test_s009/main.c b/components/TARGET_PSA/TESTS/compliance_its/test_s009/main.c deleted file mode 100644 index 74a6ddb..0000000 --- a/components/TARGET_PSA/TESTS/compliance_its/test_s009/main.c +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2020, Arm Limited and affiliates. - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include "val_interfaces.h" -#include "pal_mbed_os_intf.h" - -#if !defined(MBED_CONF_RTOS_PRESENT) -#error [NOT_SUPPORTED] PSA compliance its test cases require RTOS to run -#else - -#ifdef ITS_TEST -void test_entry_s009(val_api_t *val_api, psa_api_t *psa_api); -#elif PS_TEST -void test_entry_p009(val_api_t *val_api, psa_api_t *psa_api); -#endif - -int main(void) -{ -#ifdef ITS_TEST - test_start(test_entry_s009, COMPLIANCE_TEST_STORAGE); -#elif PS_TEST - test_start(test_entry_p009, COMPLIANCE_TEST_STORAGE); -#endif -} -#endif // !defined(MBED_CONF_RTOS_PRESENT) diff --git a/components/TARGET_PSA/TESTS/compliance_its/test_s009/test_entry.c b/components/TARGET_PSA/TESTS/compliance_its/test_s009/test_entry.c deleted file mode 100644 index 37883fb..0000000 --- a/components/TARGET_PSA/TESTS/compliance_its/test_s009/test_entry.c +++ /dev/null @@ -1,53 +0,0 @@ -/** @file - * Copyright (c) 2019, Arm Limited or its affiliates. All rights reserved. - * SPDX-License-Identifier : Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -**/ - -#include "val_interfaces.h" -#include "val_target.h" -#include "test_s009.h" - -#define TEST_NUM VAL_CREATE_TEST_ID(VAL_STORAGE_BASE, 9) -#define TEST_DESC "Invalid Arguments check\n" - -TEST_PUBLISH(TEST_NUM, test_entry); -val_api_t *val = NULL; -psa_api_t *psa = NULL; - -void test_entry(val_api_t *val_api, psa_api_t *psa_api) -{ - int32_t status = VAL_STATUS_SUCCESS; - - val = val_api; - psa = psa_api; - - /* test init */ - val->test_init(TEST_NUM, TEST_DESC, TEST_FIELD(TEST_ISOLATION_L1, WD_HIGH_TIMEOUT)); - if (!IS_TEST_START(val->get_status())) - { - goto test_exit; - } - - /* Execute list of tests available in test[num]_secure_storage_list from Non-secure side*/ - status = val->execute_non_secure_tests(TEST_NUM, test_s009_sst_list, FALSE); - - if (VAL_ERROR(status)) - { - goto test_exit; - } - -test_exit: - val->test_exit(); -} diff --git a/components/TARGET_PSA/TESTS/compliance_its/test_s009/test_its_data.h b/components/TARGET_PSA/TESTS/compliance_its/test_s009/test_its_data.h deleted file mode 100644 index 80e7fb1..0000000 --- a/components/TARGET_PSA/TESTS/compliance_its/test_s009/test_its_data.h +++ /dev/null @@ -1,69 +0,0 @@ -/** @file - * Copyright (c) 2019, Arm Limited or its affiliates. All rights reserved. - * SPDX-License-Identifier : Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -**/ -#ifndef _TEST_S009_ITS_DATA_TESTS_H_ -#define _TEST_S009_ITS_DATA_TESTS_H_ - -#include "val_internal_trusted_storage.h" - -#define SST_FUNCTION val->its_function -#define psa_sst_uid_t psa_its_uid_t - -typedef struct { - enum its_function_code api; - psa_its_status_t status; -} test_data; - -static struct psa_its_info_t info; -static const test_data s009_data[] = { -{ - 0, 0 /* This is dummy for index0 */ -}, -{ - VAL_ITS_SET, PSA_ITS_SUCCESS /* Call set API with NULL write buffer and 0 length */ -}, -{ - VAL_ITS_GET_INFO, PSA_ITS_SUCCESS /* Verify UID is created */ -}, -{ - VAL_ITS_GET, PSA_ITS_SUCCESS /* Call get API with NULL write buffer and 0 length */ -}, -{ - VAL_ITS_REMOVE, PSA_ITS_SUCCESS /* Remove the storage entity */ -}, -{ - VAL_ITS_GET_INFO, PSA_ITS_ERROR_UID_NOT_FOUND /* Verify UID is removed */ -}, -{ - VAL_ITS_SET, PSA_ITS_SUCCESS /* Create storage of zero size and valid write buffer */ -}, -{ - VAL_ITS_GET_INFO, PSA_ITS_SUCCESS /* Call get_info API to check data size */ -}, -{ - 0, 0 /* This is dummy for index8 */ -}, -{ - VAL_ITS_GET, PSA_ITS_SUCCESS /* Call get API with 0 length and NULL read buffer */ -}, -{ - VAL_ITS_SET, PSA_ITS_SUCCESS /* Increase the asset size */ -}, -{ - VAL_ITS_REMOVE, PSA_ITS_SUCCESS /* Remove the storage entity */ -}, -}; -#endif /* _TEST_S009_ITS_DATA_TESTS_H_ */ diff --git a/components/TARGET_PSA/TESTS/compliance_its/test_s009/test_ps_data.h b/components/TARGET_PSA/TESTS/compliance_its/test_s009/test_ps_data.h deleted file mode 100644 index 129bca0..0000000 --- a/components/TARGET_PSA/TESTS/compliance_its/test_s009/test_ps_data.h +++ /dev/null @@ -1,69 +0,0 @@ -/** @file - * Copyright (c) 2019, Arm Limited or ps affiliates. All rights reserved. - * SPDX-License-Identifier : Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -**/ -#ifndef _TEST_S009_PS_DATA_TESTS_H_ -#define _TEST_S009_PS_DATA_TESTS_H_ - -#include "val_protected_storage.h" - -#define SST_FUNCTION val->ps_function -#define psa_sst_uid_t psa_ps_uid_t - -typedef struct { - enum ps_function_code api; - psa_ps_status_t status; -} test_data; - -static struct psa_ps_info_t info; -static const test_data s009_data[] = { -{ - 0, 0 /* This is dummy for index0 */ -}, -{ - VAL_PS_SET, PSA_PS_SUCCESS /* Call set API with NULL write buffer and 0 length */ -}, -{ - VAL_PS_GET_INFO, PSA_PS_SUCCESS /* Verify UID is created */ -}, -{ - VAL_PS_GET, PSA_PS_SUCCESS /* Call get API with NULL write buffer and 0 length */ -}, -{ - VAL_PS_REMOVE, PSA_PS_SUCCESS /* Remove the storage entity */ -}, -{ - VAL_PS_GET_INFO, PSA_PS_ERROR_UID_NOT_FOUND /* Verify UID is removed */ -}, -{ - VAL_PS_SET, PSA_PS_SUCCESS /* Create storage of zero size and valid write buffer */ -}, -{ - VAL_PS_GET_INFO, PSA_PS_SUCCESS /* Call get_info API to check data size */ -}, -{ - 0, 0 /* This is dummy for index8 */ -}, -{ - VAL_PS_GET, PSA_PS_SUCCESS /* Call get API with 0 length and NULL read buffer */ -}, -{ - VAL_PS_SET, PSA_PS_SUCCESS /* Increase the asset size */ -}, -{ - VAL_PS_REMOVE, PSA_PS_SUCCESS /* Remove the storage entity */ -}, -}; -#endif /* _TEST_S009_PS_DATA_TESTS_H_ */ diff --git a/components/TARGET_PSA/TESTS/compliance_its/test_s009/test_s009.c b/components/TARGET_PSA/TESTS/compliance_its/test_s009/test_s009.c deleted file mode 100644 index c54fa02..0000000 --- a/components/TARGET_PSA/TESTS/compliance_its/test_s009/test_s009.c +++ /dev/null @@ -1,92 +0,0 @@ -/** @file - * Copyright (c) 2019, Arm Limited or its affiliates. All rights reserved. - * SPDX-License-Identifier : Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -**/ - -#include "val_interfaces.h" -#include "val_target.h" -#include "test_s009.h" -#ifdef ITS_TEST -#include "test_its_data.h" -#elif PS_TEST -#include "test_ps_data.h" -#endif - -#define TEST_BUFF_SIZE 20 - -client_test_t test_s009_sst_list[] = { - NULL, - psa_sst_zero_length_check, - NULL, -}; - -static psa_sst_uid_t uid = UID_BASE_VALUE + 5; -static uint8_t write_buff[TEST_BUFF_SIZE] = {0x99, 0x01, 0x02, 0x03, 0x04, 0x23, 0xF6, 0x07, 0x08, \ - 0x0D, 0x70, 0xA1, 0xFF, 0xFF, 0x14, 0x73, 0x46, 0x97, 0xE8, 0xDD}; - -int32_t psa_sst_zero_length_check(caller_security_t caller) -{ - uint32_t status; - - /* Set data for UID with length 0 and NULL pointer */ - val->print(PRINT_TEST, "[Check 1] Call set API with NULL pointer and data length 0\n", 0); - status = SST_FUNCTION(s009_data[1].api, uid, 0, NULL, 0); - TEST_ASSERT_EQUAL(status, s009_data[1].status, TEST_CHECKPOINT_NUM(1)); - - /* Call the get_info function to verify UID created */ - status = SST_FUNCTION(s009_data[2].api, uid, &info); - TEST_ASSERT_EQUAL(status, s009_data[2].status, TEST_CHECKPOINT_NUM(2)); - - /* Call get API with NULL read buffer */ - val->print(PRINT_TEST, "[Check 2] Call get API with NULL read buffer and data length 0\n", 0); - status = SST_FUNCTION(s009_data[3].api, uid, 0, 0, NULL); - TEST_ASSERT_EQUAL(status, s009_data[3].status, TEST_CHECKPOINT_NUM(3)); - - /* Remove the UID */ - val->print(PRINT_TEST, "[Check 3] Remove the UID\n", 0); - status = SST_FUNCTION(s009_data[4].api, uid); - TEST_ASSERT_EQUAL(status, s009_data[4].status, TEST_CHECKPOINT_NUM(4)); - - /* Call the get_info function to verify UID is removed */ - val->print(PRINT_TEST, "[Check 4] Call get_info API to verify UID removed\n", 0); - status = SST_FUNCTION(s009_data[5].api, uid, &info); - TEST_ASSERT_EQUAL(status, s009_data[5].status, TEST_CHECKPOINT_NUM(5)); - - /* Create UID with length 0 and valid write buffer */ - val->print(PRINT_TEST, "[Check 5] Create UID with zero data_len and valid write buffer\n", 0); - status = SST_FUNCTION(s009_data[6].api, uid, 0, write_buff, 0); - TEST_ASSERT_EQUAL(status, s009_data[6].status, TEST_CHECKPOINT_NUM(6)); - - /* Call the get_info function and match the attributes */ - status = SST_FUNCTION(s009_data[7].api, uid, &info); - TEST_ASSERT_EQUAL(status, s009_data[7].status, TEST_CHECKPOINT_NUM(7)); - TEST_ASSERT_EQUAL(info.size, 0, TEST_CHECKPOINT_NUM(8)); - - /* Call get API with NULL read buffer and valid UID */ - val->print(PRINT_TEST, "[Check 8] Call get API with NULL read buffer and data length 0\n", 0); - status = SST_FUNCTION(s009_data[9].api, uid, 0, 0, NULL); - TEST_ASSERT_EQUAL(status, s009_data[9].status, TEST_CHECKPOINT_NUM(9)); - - /* Change the length to test_buff_size */ - val->print(PRINT_TEST, "[Check 9] Increase the length\n", 0); - status = SST_FUNCTION(s009_data[10].api, uid, TEST_BUFF_SIZE, write_buff, 0); - TEST_ASSERT_EQUAL(status, s009_data[10].status, TEST_CHECKPOINT_NUM(10)); - - /* Remove the UID */ - status = SST_FUNCTION(s009_data[11].api, uid); - TEST_ASSERT_EQUAL(status, s009_data[11].status, TEST_CHECKPOINT_NUM(11)); - - return VAL_STATUS_SUCCESS; -} diff --git a/components/TARGET_PSA/TESTS/compliance_its/test_s009/test_s009.h b/components/TARGET_PSA/TESTS/compliance_its/test_s009/test_s009.h deleted file mode 100644 index 49a5de0..0000000 --- a/components/TARGET_PSA/TESTS/compliance_its/test_s009/test_s009.h +++ /dev/null @@ -1,36 +0,0 @@ -/** @file - * Copyright (c) 2019, Arm Limited or its affiliates. All rights reserved. - * SPDX-License-Identifier : Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -**/ -#ifndef _TEST_S009_CLIENT_TESTS_H_ -#define _TEST_S009_CLIENT_TESTS_H_ - -#ifdef ITS_TEST -#define VAL_STORAGE_BASE VAL_INTERNAL_TRUSTED_STORAGE_BASE -#define test_entry CONCAT(test_entry_, s009) -#elif PS_TEST -#define VAL_STORAGE_BASE VAL_PROTECTED_STORAGE_BASE -#define test_entry CONCAT(test_entry_, p009) -#endif -#define val CONCAT(val,test_entry) -#define psa CONCAT(psa,test_entry) - -extern val_api_t *val; -extern psa_api_t *psa; -extern client_test_t test_s009_sst_list[]; - -int32_t psa_sst_zero_length_check(caller_security_t caller); - -#endif /* _TEST_S009_CLIENT_TESTS_H_ */ diff --git a/components/TARGET_PSA/TESTS/compliance_its/test_s010/main.c b/components/TARGET_PSA/TESTS/compliance_its/test_s010/main.c deleted file mode 100644 index c9f0728..0000000 --- a/components/TARGET_PSA/TESTS/compliance_its/test_s010/main.c +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2020, Arm Limited and affiliates. - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include "val_interfaces.h" -#include "pal_mbed_os_intf.h" - -#if !defined(MBED_CONF_RTOS_PRESENT) -#error [NOT_SUPPORTED] PSA compliance its test cases require RTOS to run -#else - -#ifdef ITS_TEST -void test_entry_s010(val_api_t *val_api, psa_api_t *psa_api); -#elif PS_TEST -void test_entry_p010(val_api_t *val_api, psa_api_t *psa_api); -#endif - -int main(void) -{ -#ifdef ITS_TEST - test_start(test_entry_s010, COMPLIANCE_TEST_STORAGE); -#elif PS_TEST - test_start(test_entry_p010, COMPLIANCE_TEST_STORAGE); -#endif -} -#endif // !defined(MBED_CONF_RTOS_PRESENT) diff --git a/components/TARGET_PSA/TESTS/compliance_its/test_s010/test_entry.c b/components/TARGET_PSA/TESTS/compliance_its/test_s010/test_entry.c deleted file mode 100644 index 82623c6..0000000 --- a/components/TARGET_PSA/TESTS/compliance_its/test_s010/test_entry.c +++ /dev/null @@ -1,53 +0,0 @@ -/** @file - * Copyright (c) 2019, Arm Limited or its affiliates. All rights reserved. - * SPDX-License-Identifier : Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -**/ - -#include "val_interfaces.h" -#include "val_target.h" -#include "test_s010.h" - -#define TEST_NUM VAL_CREATE_TEST_ID(VAL_STORAGE_BASE, 10) -#define TEST_DESC "UID value zero check\n" - -TEST_PUBLISH(TEST_NUM, test_entry); -val_api_t *val = NULL; -psa_api_t *psa = NULL; - -void test_entry(val_api_t *val_api, psa_api_t *psa_api) -{ - int32_t status = VAL_STATUS_SUCCESS; - - val = val_api; - psa = psa_api; - - /* test init */ - val->test_init(TEST_NUM, TEST_DESC, TEST_FIELD(TEST_ISOLATION_L1, WD_HIGH_TIMEOUT)); - if (!IS_TEST_START(val->get_status())) - { - goto test_exit; - } - - /* Execute list of tests available in test[num]_secure_storage_list from Non-secure side*/ - status = val->execute_non_secure_tests(TEST_NUM, test_s010_sst_list, FALSE); - - if (VAL_ERROR(status)) - { - goto test_exit; - } - -test_exit: - val->test_exit(); -} diff --git a/components/TARGET_PSA/TESTS/compliance_its/test_s010/test_its_data.h b/components/TARGET_PSA/TESTS/compliance_its/test_s010/test_its_data.h deleted file mode 100644 index 7b1b6d3..0000000 --- a/components/TARGET_PSA/TESTS/compliance_its/test_s010/test_its_data.h +++ /dev/null @@ -1,35 +0,0 @@ -/** @file - * Copyright (c) 2019, Arm Limited or its affiliates. All rights reserved. - * SPDX-License-Identifier : Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -**/ -#ifndef _TEST_S010_ITS_DATA_TESTS_H_ -#define _TEST_S010_ITS_DATA_TESTS_H_ - -#include "val_internal_trusted_storage.h" - -#define SST_FUNCTION val->its_function -#define psa_sst_uid_t psa_its_uid_t - -typedef struct { - enum its_function_code api; - psa_its_status_t status; -} test_data; - -static const test_data s010_data[] = { -{ - VAL_ITS_SET, PSA_ITS_SUCCESS /* Create with UID value zero should fail */ -}, -}; -#endif /* _TEST_S010_ITS_DATA_TESTS_H_ */ diff --git a/components/TARGET_PSA/TESTS/compliance_its/test_s010/test_ps_data.h b/components/TARGET_PSA/TESTS/compliance_its/test_s010/test_ps_data.h deleted file mode 100644 index e88ed9b..0000000 --- a/components/TARGET_PSA/TESTS/compliance_its/test_s010/test_ps_data.h +++ /dev/null @@ -1,35 +0,0 @@ -/** @file - * Copyright (c) 2019, Arm Limited or ps affiliates. All rights reserved. - * SPDX-License-Identifier : Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -**/ -#ifndef _TEST_S010_PS_DATA_TESTS_H_ -#define _TEST_S010_PS_DATA_TESTS_H_ - -#include "val_protected_storage.h" - -#define SST_FUNCTION val->ps_function -#define psa_sst_uid_t psa_ps_uid_t - -typedef struct { - enum ps_function_code api; - psa_ps_status_t status; -} test_data; - -static const test_data s010_data[] = { -{ - VAL_PS_SET, PSA_PS_SUCCESS /* Create with UID value zero should fail */ -}, -}; -#endif /* _TEST_S010_PS_DATA_TESTS_H_ */ diff --git a/components/TARGET_PSA/TESTS/compliance_its/test_s010/test_s010.c b/components/TARGET_PSA/TESTS/compliance_its/test_s010/test_s010.c deleted file mode 100644 index 380c069..0000000 --- a/components/TARGET_PSA/TESTS/compliance_its/test_s010/test_s010.c +++ /dev/null @@ -1,49 +0,0 @@ -/** @file - * Copyright (c) 2019, Arm Limited or its affiliates. All rights reserved. - * SPDX-License-Identifier : Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -**/ - -#include "val_interfaces.h" -#include "val_target.h" -#include "test_s010.h" -#ifdef ITS_TEST -#include "test_its_data.h" -#elif PS_TEST -#include "test_ps_data.h" -#endif - -#define TEST_BUFF_SIZE 1 - -client_test_t test_s010_sst_list[] = { - NULL, - psa_sst_uid_value_zero_check, - NULL, -}; - -static uint8_t write_buff[TEST_BUFF_SIZE] = {0xFF}; - -int32_t psa_sst_uid_value_zero_check(caller_security_t caller) -{ - int32_t status; - psa_sst_uid_t uid = 0; - - /* Set with UID value zero should fail */ - val->print(PRINT_TEST, "[Check 1] Creating storage with UID 0 should fail\n", 0 ); - status = SST_FUNCTION(s010_data[0].api, uid, TEST_BUFF_SIZE, write_buff, 0); - TEST_ASSERT_NOT_EQUAL(status, s010_data[0].status, TEST_CHECKPOINT_NUM(1)); - - return VAL_STATUS_SUCCESS; -} - diff --git a/components/TARGET_PSA/TESTS/compliance_its/test_s010/test_s010.h b/components/TARGET_PSA/TESTS/compliance_its/test_s010/test_s010.h deleted file mode 100644 index 35dfb7c..0000000 --- a/components/TARGET_PSA/TESTS/compliance_its/test_s010/test_s010.h +++ /dev/null @@ -1,35 +0,0 @@ -/** @file - * Copyright (c) 2019, Arm Limited or its affiliates. All rights reserved. - * SPDX-License-Identifier : Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -**/ -#ifndef _TEST_S010_CLIENT_TESTS_H_ -#define _TEST_S010_CLIENT_TESTS_H_ - -#ifdef ITS_TEST -#define VAL_STORAGE_BASE VAL_INTERNAL_TRUSTED_STORAGE_BASE -#define test_entry CONCAT(test_entry_, s010) -#elif PS_TEST -#define VAL_STORAGE_BASE VAL_PROTECTED_STORAGE_BASE -#define test_entry CONCAT(test_entry_, p010) -#endif -#define val CONCAT(val,test_entry) -#define psa CONCAT(psa,test_entry) - -extern val_api_t *val; -extern psa_api_t *psa; -extern client_test_t test_s010_sst_list[]; - -int32_t psa_sst_uid_value_zero_check(caller_security_t caller); -#endif /* _TEST_S010_CLIENT_TESTS_H_ */ diff --git a/components/TARGET_PSA/inc/psa/client.h b/components/TARGET_PSA/inc/psa/client.h deleted file mode 100644 index effc0ce..0000000 --- a/components/TARGET_PSA/inc/psa/client.h +++ /dev/null @@ -1,57 +0,0 @@ -/* Copyright (c) 2017-2018 ARM Limited - * - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#if defined(TARGET_TFM) -#include "interface/include/psa_client.h" -#else - -#ifndef __MBED_OS_DEFAULT_PSA_CLIENT_API_H__ -#define __MBED_OS_DEFAULT_PSA_CLIENT_API_H__ - -#include -#include "psa/error.h" - -#if !defined(UINT32_MAX) -#define UINT32_MAX ((uint32_t)-1) -#endif - -#if !defined(INT32_MIN) -#define INT32_MIN (-0x7fffffff - 1) -#endif - -#define PSA_FRAMEWORK_VERSION (0x0100) /**< Version of the PSA Framework API. */ -#define PSA_VERSION_NONE (0L) /**< Identifier for an unimplemented Root of Trust (RoT) Service. */ -#define PSA_CONNECTION_REFUSED (INT32_MIN + 1) /**< The return value from psa_connect() if the RoT Service or SPM was unable to establish a connection.*/ -#define PSA_CONNECTION_BUSY (INT32_MIN + 2) /**< The return value from psa_connect() if the RoT Service rejects the connection for a transient reason.*/ -#define PSA_DROP_CONNECTION (INT32_MIN) /**< The result code in a call to psa_reply() to indicate a nonrecoverable error in the client.*/ -#define PSA_NULL_HANDLE ((psa_handle_t)0) /**< Denotes an invalid handle.*/ - -typedef int32_t psa_handle_t; - -typedef struct psa_invec { - const void *base; /**< Starting address of the buffer.*/ - size_t len; /**< Length in bytes of the buffer.*/ -} psa_invec; - - -typedef struct psa_outvec { - void *base; /**< Starting address of the buffer.*/ - size_t len; /**< Length in bytes of the buffer.*/ -} psa_outvec; - -#endif // __MBED_OS_DEFAULT_PSA_CLIENT_API_H__ -#endif diff --git a/components/TARGET_PSA/inc/psa/error.h b/components/TARGET_PSA/inc/psa/error.h deleted file mode 100644 index ba0e0e3..0000000 --- a/components/TARGET_PSA/inc/psa/error.h +++ /dev/null @@ -1,56 +0,0 @@ -/* -* Copyright (c) 2019 ARM Limited. All rights reserved. -* -* SPDX-License-Identifier: Apache-2.0 -* -* Licensed under the Apache License, Version 2.0 (the License); you may -* not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an AS IS BASIS, WITHOUT -* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -/* psa/error.h -Standard error codes for the SPM and RoT Services -As defined in PSA Firmware Framework v1.0 -*/ - -#ifndef __PSA_ERROR__ -#define __PSA_ERROR__ - -#include -#include - -typedef int32_t psa_status_t; - -#define PSA_SUCCESS ((psa_status_t)0) - -#define PSA_ERROR_PROGRAMMER_ERROR ((psa_status_t)-129) -#define PSA_ERROR_CONNECTION_REFUSED ((psa_status_t)-130) -#define PSA_ERROR_CONNECTION_BUSY ((psa_status_t)-131) -#define PSA_ERROR_GENERIC_ERROR ((psa_status_t)-132) -#define PSA_ERROR_NOT_PERMITTED ((psa_status_t)-133) -#define PSA_ERROR_NOT_SUPPORTED ((psa_status_t)-134) -#define PSA_ERROR_INVALID_ARGUMENT ((psa_status_t)-135) -#define PSA_ERROR_INVALID_HANDLE ((psa_status_t)-136) -#define PSA_ERROR_BAD_STATE ((psa_status_t)-137) -#define PSA_ERROR_BUFFER_TOO_SMALL ((psa_status_t)-138) -#define PSA_ERROR_ALREADY_EXISTS ((psa_status_t)-139) -#define PSA_ERROR_DOES_NOT_EXIST ((psa_status_t)-140) -#define PSA_ERROR_INSUFFICIENT_MEMORY ((psa_status_t)-141) -#define PSA_ERROR_INSUFFICIENT_STORAGE ((psa_status_t)-142) -#define PSA_ERROR_INSUFFICIENT_DATA ((psa_status_t)-143) -#define PSA_ERROR_SERVICE_FAILURE ((psa_status_t)-144) -#define PSA_ERROR_COMMUNICATION_FAILURE ((psa_status_t)-145) -#define PSA_ERROR_STORAGE_FAILURE ((psa_status_t)-146) -#define PSA_ERROR_HARDWARE_FAILURE ((psa_status_t)-147) -#define PSA_ERROR_INVALID_SIGNATURE ((psa_status_t)-149) -#define PSA_ERROR_DATA_CORRUPT ((psa_status_t)-152) - -#endif // __PSA_ERROR__ diff --git a/components/TARGET_PSA/inc/psa/internal_trusted_storage.h b/components/TARGET_PSA/inc/psa/internal_trusted_storage.h deleted file mode 100644 index 7b3b6a9..0000000 --- a/components/TARGET_PSA/inc/psa/internal_trusted_storage.h +++ /dev/null @@ -1,23 +0,0 @@ -/* Copyright (c) 2017-2018 ARM Limited - * - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef __MBED_INTERNAL_TRUSTED_STORAGE_H__ -#define __MBED_INTERNAL_TRUSTED_STORAGE_H__ - -#include "psa_prot_internal_storage.h" - -#endif // __MBED_INTERNAL_TRUSTED_STORAGE_H__ diff --git a/components/TARGET_PSA/inc/psa/lifecycle.h b/components/TARGET_PSA/inc/psa/lifecycle.h deleted file mode 100644 index 1afa44f..0000000 --- a/components/TARGET_PSA/inc/psa/lifecycle.h +++ /dev/null @@ -1,79 +0,0 @@ -/* Copyright (c) 2018 ARM Limited - * - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef __LIFECYCLE_H__ -#define __LIFECYCLE_H__ - -/** @file -@brief This file describes the PSA RoT Lifecycle API -*/ - -#include -#include -#include "mbed_toolchain.h" -#include "psa/error.h" - -#ifdef __cplusplus -extern "C" -{ -#endif - -#define PSA_LIFECYCLE_STATE_MASK (0xff00u) /**< A mask value that extracts the main lifecycle state */ -#define PSA_LIFECYCLE_SUBSTATE_MASK (0x00ffu) /**< A mask value that extracts the IMPLEMENTATION DEFINED lifecycle sub-state */ - -#define PSA_LIFECYCLE_UNKNOWN (0x0000u) /**< State is unknown */ -#define PSA_LIFECYCLE_ASSEMBLY_AND_TEST (0x1000u) /**< Assembly and Test state */ -#define PSA_LIFECYCLE_PSA_ROT_PROVISIONING (0x2000u) /**< PSA RoT Provisioning state */ -#define PSA_LIFECYCLE_SECURED (0x3000u) /**< Secured state */ -#define PSA_LIFECYCLE_NON_PSA_ROT_DEBUG (0x4000u) /**< Non PSA RoT debug state */ -#define PSA_LIFECYCLE_RECOVERABLE_PSA_ROT_DEBUG (0x5000u) /**< Recoverable PSA RoT Debug state */ -#define PSA_LIFECYCLE_DECOMMISSIONED (0x6000u) /**< Decommissioned state */ - -/** \brief Get PSA RoT lifecycle state - * - * \retval The main state and sub-state are encoded as follows:@n - @a version[15:8] – main lifecycle state - @a version[7:0] – IMPLEMENTATION DEFINED sub-state - */ -uint32_t psa_security_lifecycle_state(void); - -/** \brief Request state change - * - * State change requested and the reset the system. - * \note System reset will not be performed when switching from PSA_LIFECYCLE_ASSEMBLY_AND_TEST - * to PSA_LIFECYCLE_ASSEMBLY_AND_TEST. - * - * \note state change to follwing states will delete PSA internal storage: - * - PSA_LIFECYCLE_ASSEMBLY_AND_TEST - * - PSA_LIFECYCLE_PSA_ROT_PROVISIONING - * - PSA_LIFECYCLE_DECOMMISSIONED - */ -psa_status_t mbed_psa_reboot_and_request_new_security_state(uint32_t new_state); - - -/** \brief Resets the system - * - * PSA targets do not allow NSPE to access system power domain. - * This API requests system reset to be carried out by SPE once all critical secure tasks are finished. - */ -MBED_NORETURN void mbed_psa_system_reset(); - -#ifdef __cplusplus -} -#endif - -#endif // __LIFECYCLE_H__ diff --git a/components/TARGET_PSA/inc/psa/protected_storage.h b/components/TARGET_PSA/inc/psa/protected_storage.h deleted file mode 100644 index 6b299a3..0000000 --- a/components/TARGET_PSA/inc/psa/protected_storage.h +++ /dev/null @@ -1,202 +0,0 @@ -/* Copyright (C) 2019, ARM Limited, All Rights Reserved - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** @file -@brief This file describes the PSA Protected Storage API -*/ - -#ifndef __PSA_PROTECTED_STORAGE_H__ -#define __PSA_PROTECTED_STORAGE_H__ - -#include -#include - -#include "psa/error.h" -#include "psa/storage_common.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define PSA_PS_API_VERSION_MAJOR 1 /**< The major version number of the PSA PS API. It will be incremented on significant updates that may include breaking changes */ -#define PSA_PS_API_VERSION_MINOR 1 /**< The minor version number of the PSA PS API. It will be incremented in small updates that are unlikely to include breaking changes */ - - -/** - * \brief create a new or modify an existing key/value pair - * - * \param[in] uid the identifier for the data - * \param[in] data_length The size in bytes of the data in `p_data` - * \param[in] p_data A buffer containing the data - * \param[in] create_flags The flags indicating the properties of the data - * - * \return A status indicating the success/failure of the operation - - * \retval PSA_SUCCESS The operation completed successfully - * \retval PSA_ERROR_NOT_PERMITTED The operation failed because the provided uid value was already created with PSA_STORAGE_WRITE_ONCE_FLAG - * \retval PSA_ERROR_INVALID_ARGUMENT The operation failed because one or more of the given arguments were invalid. - * \retval PSA_ERROR_NOT_SUPPORTED The operation failed because one or more of the flags provided in `create_flags` is not supported or is not valid - * \retval PSA_ERROR_INSUFFICIENT_STORAGE The operation failed because there was insufficient space on the storage medium - * \retval PSA_ERROR_STORAGE_FAILURE The operation failed because the physical storage has failed (Fatal error) - * \retval PSA_ERROR_GENERIC_ERROR The operation failed because of an unspecified internal failure - */ -psa_status_t psa_ps_set(psa_storage_uid_t uid, - size_t data_length, - const void *p_data, - psa_storage_create_flags_t create_flags); - -/** - * \brief Retrieve the value for a provided uid - * - * \param[in] uid The identifier for the data - * \param[in] data_offset The offset within the data associated with the `uid` to start retrieving data - * \param[in] data_length The amount of data to read (and the minimum allocated size of the `p_data` buffer) - * \param[out] p_data The buffer where the data will be placed upon successful completion - * \param[out] p_data_length The actual amount of data returned - * - * \return A status indicating the success/failure of the operation - * - * \retval PSA_SUCCESS The operation completed successfully - * \retval PSA_ERROR_INVALID_ARGUMENT The operation failed because one or more of the given arguments were invalid (null pointer, wrong flags etc.) - * \retval PSA_ERROR_DOES_NOT_EXIST The operation failed because the provided uid value was not found in the storage - * \retval PSA_ERROR_BUFFER_TOO_SMALL The operation failed because the data associated with provided uid does not fit `data_size` - * \retval PSA_ERROR_STORAGE_FAILURE The operation failed because the physical storage has failed (Fatal error) - * \retval PSA_ERROR_GENERIC_ERROR The operation failed because of an unspecified internal failure - * \retval PSA_ERROR_DATA_CORRUPT The operation failed because of an authentication failure when attempting to get the key - * \retval PSA_ERROR_INVALID_SIGNATURE The operation failed because the data associated with the UID failed authentication - */ -psa_status_t psa_ps_get(psa_storage_uid_t uid, - size_t data_offset, - size_t data_length, - void *p_data, - size_t *p_data_length); - -/** - * \brief Retrieve the metadata about the provided uid - * - * \param[in] uid The identifier for the data - * \param[out] p_info A pointer to the `psa_storage_info_t` struct that will be populated with the metadata - * - * \return A status indicating the success/failure of the operation - * - * \retval PSA_SUCCESS The operation completed successfully - * \retval PSA_ERROR_INVALID_ARGUMENT The operation failed because one or more of the given arguments were invalid (null pointer, wrong flags etc.) - * \retval PSA_ERROR_DOES_NOT_EXIST The operation failed because the provided uid value was not found in the storage - * \retval PSA_ERROR_STORAGE_FAILURE The operation failed because the physical storage has failed (Fatal error) - * \retval PSA_ERROR_GENERIC_ERROR The operation failed because of an unspecified internal failure - * \retval PSA_ERROR_DATA_CORRUPT The operation failed because of an authentication failure when attempting to get the key - * \retval PSA_ERROR_INVALID_SIGNATURE The operation failed because the data associated with the UID failed authentication - */ -psa_status_t psa_ps_get_info(psa_storage_uid_t uid, struct psa_storage_info_t *p_info); - -/** - * \brief Remove the provided uid and its associated data from the storage - * - * \param[in] uid The identifier for the data to be removed - * - * \return A status indicating the success/failure of the operation - * - * \retval PSA_SUCCESS The operation completed successfully - * \retval PSA_ERROR_INVALID_ARGUMENT The operation failed because one or more of the given arguments were invalid (null pointer, wrong flags etc.) - * \retval PSA_ERROR_DOES_NOT_EXIST The operation failed because the provided uid value was not found in the storage - * \retval PSA_ERROR_NOT_PERMITTED The operation failed because the provided uid value was created with psa_eps_WRITE_ONCE_FLAG - * \retval PSA_ERROR_STORAGE_FAILURE The operation failed because the physical storage has failed (Fatal error) - * \retval PSA_ERROR_GENERIC_ERROR The operation failed because of an unspecified internal failure - */ -psa_status_t psa_ps_remove(psa_storage_uid_t uid); - -/** - * Creates an asset based on the given identifier, the maximum size and - * creation flags. This create allocates the space in the secure storage - * area without setting any data in the asset. - * - * It is only necessary to call this function for items that will be written - * with the \ref psa_ps_set_extended function. If only the \ref psa_ps_set function - * is needed, calls to this function are redundant. - * - * If the \ref PSA_STORAGE_FLAG_WRITE_ONCE flag is passed, implementations should - * return \ref PSA_ERROR_NOT_SUPPORTED. - * - * This function is optional. Not all PSA Protected Storage Implementations - * will implement this function. Consult the documentation of your chosen - * platform to determine if it is present. - * - * \param[in] uid A unique identifier for the asset. - * \param[in] size The maximum size in bytes of the asset. - * \param[in] create_flags Create flags \ref psa_storage_create_flags_t. - * - * \retval PSA_SUCCESS The assest does not exist and the input parameters are correct or - * the asset already exists, the input parameters are the same that - * have been used to create the asset and the owner is the same and the current asset content is kept - * TDB: "Owner is the same" doesn't really make sense from a PSA perspective, as each partition - * has its own UID space, making other partitions' data unadressable - * \retval PSA_ERROR_STORAGE_FAILURE The create action has a physical storage error - * \retval PSA_ERROR_INSUFFICIENT_STORAGE The maximum size is bigger of the current available space - * \retval PSA_ERROR_NOT_SUPPORTED One or more create_flags are not valid or supported - * \retval PSA_ERROR_INVALID_ARGUMENT The asset exists and the input paramters are not the same as the existing asset - * \retval PSA_ERROR_NOT_SUPPORTED The implementation of the API does not support this function - * \retval PSA_ERROR_GENERIC_ERROR The operation has failed due to an unspecified error - */ -psa_status_t psa_ps_create(psa_storage_uid_t uid, - size_t size, - psa_storage_create_flags_t create_flags); - -/** - * Sets partial data into an asset based on the given identifier, data_offset, - * data length and p_data. - * - * Before calling this function, the asset must have been created with a call - * to \ref psa_ps_create. - * - * This function is optional. Not all PSA Protected Storage Implementations - * will implement this function. Consult the documentation of your chosen - * platform to determine if it is present. - * - * \param[in] uid The unique identifier for the asset. - * \param[in] data_offset Offset within the asset to start the write. - * \param[in] data_length The size in bytes of the data in p_data to write. - * \param[in] p_data Pointer to a buffer which contains the data to write. - * - * \retval PSA_SUCCESS If the asset exists, the input parameters are correct and the data - * is correctly written in the physical storage - * \retval PSA_ERROR_STORAGE_FAILURE If the data is not written correctly in the physical storage - * \retval PSA_ERROR_INVALID_ARGUMENT The operation failed because one or more of the given arguments were invalid (null pointer, wrong flags, etc) - * \retval PSA_ERROR_DOES_NOT_EXIST The specified UID was not found - * \retval PSA_ERROR_NOT_SUPPORTED The implementation of the API does not support this function - * \retval PSA_ERROR_GENERIC_ERROR The operation failed due to an unspecified error - * \retval PSA_ERROR_DATA_CORRUPT The operation failed because the existing data has been corrupted - * \retval PSA_ERROR_INVALID_SIGNATURE The operation failed because the existing data failed authentication (MAC check failed) - */ -psa_status_t psa_ps_set_extended(psa_storage_uid_t uid, - size_t data_offset, - size_t data_length, - const void *p_data); - -/** - * Returns a bitmask with flags set for all of the optional features supported - * by the implementation. - * - * Currently defined flags are limited to: - * - \ref PSA_STORAGE_SUPPORT_SET_EXTENDED - */ -uint32_t psa_ps_get_support(void); - -#ifdef __cplusplus -} -#endif - - -#endif // __PSA_PROTECTED_STORAGE_H__ diff --git a/components/TARGET_PSA/inc/psa/service.h b/components/TARGET_PSA/inc/psa/service.h deleted file mode 100644 index 355c966..0000000 --- a/components/TARGET_PSA/inc/psa/service.h +++ /dev/null @@ -1,28 +0,0 @@ -/* Copyright (c) 2017-2018 ARM Limited - * - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#if defined(TARGET_TFM) - -#include "interface/include/psa_service.h" -#include "secure_fw/core/ipc/include/tfm_utils.h" -#define SPM_PANIC(format, ...) tfm_panic() - -#else - -#error "Compiling psa service header on non-secure target is not allowed" - -#endif diff --git a/components/TARGET_PSA/inc/psa/storage_common.h b/components/TARGET_PSA/inc/psa/storage_common.h deleted file mode 100644 index 1747f14..0000000 --- a/components/TARGET_PSA/inc/psa/storage_common.h +++ /dev/null @@ -1,64 +0,0 @@ -/* Copyright (C) 2019, ARM Limited, All Rights Reserved - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** @file -@brief This file includes common definitions for PSA storage -*/ - -#ifndef __PSA_STORAGE_COMMON_H__ -#define __PSA_STORAGE_COMMON_H__ - -#include -#include -#include "psa/error.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** \brief Flags used when creating a data entry - */ -typedef uint32_t psa_storage_create_flags_t; - -#define PSA_STORAGE_FLAG_NONE 0 /**< No flags to pass */ -#define PSA_STORAGE_FLAG_WRITE_ONCE (1 << 0) /**< The data associated with the uid will not be able to be modified or deleted. Intended to be used to set bits in `psa_storage_create_flags_t`*/ -#define PSA_STORAGE_FLAG_NO_CONFIDENTIALITY (1 << 1) /**< The data associated with the uid is public and therefore does not require confidentiality. It therefore only needs to be integrity protected */ -#define PSA_STORAGE_FLAG_NO_REPLAY_PROTECTION (1 << 2) /**< The data associated with the uid does not require replay protection. This may permit faster storage - but it permits an attecker with physical access to revert to an earlier version of the data. */ - -/** \brief A type for UIDs used for identifying data - */ -typedef uint64_t psa_storage_uid_t; - -/** - * \brief A container for metadata associated with a specific uid - */ -struct psa_storage_info_t { - size_t capacity; /**< The allocated capacity of the storage associated with a UID **/ - size_t size; /**< The size of the data associated with a uid **/ - psa_storage_create_flags_t flags; /**< The flags set when the uid was created **/ -}; - -/** \brief Flag indicating that \ref psa_storage_create and \ref psa_storage_set_extended are supported */ -#define PSA_STORAGE_SUPPORT_SET_EXTENDED (1 << 0) - -/** \brief PSA storage specific error codes */ -#define PSA_ERROR_DATA_CORRUPT ((psa_status_t)-152) - -#ifdef __cplusplus -} -#endif - -#endif // __PSA_STORAGE_COMMON_H__ diff --git a/components/TARGET_PSA/inc/psa_manifest/sid.h b/components/TARGET_PSA/inc/psa_manifest/sid.h deleted file mode 100644 index 42fe92b..0000000 --- a/components/TARGET_PSA/inc/psa_manifest/sid.h +++ /dev/null @@ -1,23 +0,0 @@ -/* Copyright (c) 2017-2018 ARM Limited - * - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef __SID_H__ -#define __SID_H__ - -#include "autogen_sid.h" - -#endif // __SID_H__ diff --git a/components/TARGET_PSA/services/COMPONENT_PSA_SRV_IMPL/mbed_lib.json b/components/TARGET_PSA/services/COMPONENT_PSA_SRV_IMPL/mbed_lib.json deleted file mode 100644 index ac6c485..0000000 --- a/components/TARGET_PSA/services/COMPONENT_PSA_SRV_IMPL/mbed_lib.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "name": "psa-services", - "requires": [ - "drivers", - "platform", - "mbedtls", - "storage", - "flashiap-block-device", - "tdbstore", - "storage_tdb_internal" - ] -} diff --git a/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_EMUL/psa_attest_inject_key.c b/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_EMUL/psa_attest_inject_key.c deleted file mode 100755 index acb93a6..0000000 --- a/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_EMUL/psa_attest_inject_key.c +++ /dev/null @@ -1,38 +0,0 @@ -/* -* Copyright (c) 2018-2019 ARM Limited. All rights reserved. -* -* SPDX-License-Identifier: Apache-2.0 -* -* Licensed under the Apache License, Version 2.0 (the License); you may -* not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an AS IS BASIS, WITHOUT -* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#include "psa_attest_inject_key.h" -#include "psa_inject_attestation_key_impl.h" - -psa_status_t -psa_attestation_inject_key(const uint8_t *key_data, - size_t key_data_length, - psa_key_type_t type, - uint8_t *public_key_data, - size_t public_key_data_size, - size_t *public_key_data_length) -{ - psa_status_t status = PSA_SUCCESS; - status = psa_attestation_inject_key_impl(key_data, - key_data_length, - type, - public_key_data, - public_key_data_size, - public_key_data_length); - return (status); -} diff --git a/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_EMUL/psa_initial_attestation_api.c b/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_EMUL/psa_initial_attestation_api.c deleted file mode 100755 index c4eb017..0000000 --- a/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_EMUL/psa_initial_attestation_api.c +++ /dev/null @@ -1,70 +0,0 @@ -/* -* Copyright (c) 2018-2019 ARM Limited. All rights reserved. -* -* SPDX-License-Identifier: Apache-2.0 -* -* Licensed under the Apache License, Version 2.0 (the License); you may -* not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an AS IS BASIS, WITHOUT -* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#include "psa_initial_attestation_api.h" -#include "psa/client.h" -#include "attestation.h" -#include - -int32_t g_caller_id = 0; - -enum psa_attest_err_t -psa_initial_attest_get_token(const uint8_t *challenge_obj, - uint32_t challenge_size, - uint8_t *token, - uint32_t *token_size) { - enum psa_attest_err_t err; - - err = attest_init(); - if (err != PSA_ATTEST_ERR_SUCCESS) - { - return err; - } - - psa_invec in_vec[1] = { { challenge_obj, challenge_size } }; - psa_outvec out_vec[1] = { { token, *token_size } }; - - err = initial_attest_get_token(in_vec, 1, out_vec, 1); - if (err != PSA_ATTEST_ERR_SUCCESS) - { - return err; - } - - *token_size = out_vec[0].len; - - return err; -} - -enum psa_attest_err_t -psa_initial_attest_get_token_size(uint32_t challenge_size, - uint32_t *token_size) { - enum psa_attest_err_t err; - - err = attest_init(); - if (err != PSA_ATTEST_ERR_SUCCESS) - { - return err; - } - - psa_invec in_vec[1] = { { &challenge_size, sizeof(challenge_size) } }; - psa_outvec out_vec[1] = { { token_size, sizeof(*token_size) } }; - - err = initial_attest_get_token_size(in_vec, 1, out_vec, 1); - - return err; -} diff --git a/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IMPL/attest_boot_status_loader.c b/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IMPL/attest_boot_status_loader.c deleted file mode 100755 index 8413a67..0000000 --- a/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IMPL/attest_boot_status_loader.c +++ /dev/null @@ -1,95 +0,0 @@ -/* -* Copyright (c) 2018-2019 ARM Limited. All rights reserved. -* -* SPDX-License-Identifier: Apache-2.0 -* -* Licensed under the Apache License, Version 2.0 (the License); you may -* not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an AS IS BASIS, WITHOUT -* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#include -#include -#include "attestation.h" -#include "attestation_bootloader_data.h" -#include "tfm_impl/tfm_boot_status.h" -#ifdef TARGET_TFM -#include "region_defs.h" -#endif - -/*! - * \def SHARED_DATA_INITIALZED and SHARED_DATA_UNNITIALZED - * - * \brief Indicates that shared data was already initialized. - */ -#define SHARED_DATA_UNNITIALZED (0u) -#define SHARED_DATA_INITIALZED (1u) - -/*! - * \var shared_data_init_done - * - * \brief Indicates whether shared data area was already initialized. - * - */ -static uint32_t shared_data_init_done = SHARED_DATA_UNNITIALZED; - -enum psa_attest_err_t -attest_get_boot_data(uint8_t major_type, void *ptr, uint32_t len) { - if (shared_data_init_done == SHARED_DATA_INITIALZED) - { - return PSA_ATTEST_ERR_SUCCESS; - } - struct shared_data_tlv_header *tlv_header; - struct shared_data_tlv_header *ptr_tlv_header; - struct shared_data_tlv_entry *tlv_entry; - uintptr_t tlv_end, offset; - - /* Get the boundaries of TLV section */ - tlv_header = (struct shared_data_tlv_header *)BOOT_TFM_SHARED_DATA_BASE; - if (tlv_header->tlv_magic != SHARED_DATA_TLV_INFO_MAGIC) - { - return PSA_ATTEST_ERR_INIT_FAILED; - } - tlv_end = (uintptr_t)BOOT_TFM_SHARED_DATA_BASE + (uintptr_t)tlv_header->tlv_tot_len; - offset = (uintptr_t)BOOT_TFM_SHARED_DATA_BASE + (uintptr_t)SHARED_DATA_HEADER_SIZE; - - /* Add header to output buffer as well */ - if (len < SHARED_DATA_HEADER_SIZE) - { - return PSA_ATTEST_ERR_INIT_FAILED; - } - ptr_tlv_header = (struct shared_data_tlv_header *)ptr; - ptr_tlv_header->tlv_magic = SHARED_DATA_TLV_INFO_MAGIC; - ptr_tlv_header->tlv_tot_len = SHARED_DATA_HEADER_SIZE; - - ptr = (uint8_t *)ptr + SHARED_DATA_HEADER_SIZE; - /* Iterates over the TLV section and copy TLVs with requested major - * type to the provided buffer. - */ - for (; offset < tlv_end; offset += tlv_entry->tlv_len) - { - tlv_entry = (struct shared_data_tlv_entry *)offset; - if (GET_MAJOR(tlv_entry->tlv_type) == major_type) { - if (len < ptr_tlv_header->tlv_tot_len + tlv_entry->tlv_len) { - return PSA_ATTEST_ERR_INIT_FAILED; - } - memcpy(ptr, (const void *)tlv_entry, tlv_entry->tlv_len); - ptr = (uint8_t *)ptr + tlv_entry->tlv_len; - ptr_tlv_header->tlv_tot_len += tlv_entry->tlv_len; - } - if (tlv_entry->tlv_len == 0) { - break; - } - } - - shared_data_init_done = SHARED_DATA_INITIALZED; - return PSA_ATTEST_ERR_SUCCESS; -} diff --git a/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IMPL/attest_crypto.c b/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IMPL/attest_crypto.c deleted file mode 100755 index f92fc18..0000000 --- a/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IMPL/attest_crypto.c +++ /dev/null @@ -1,275 +0,0 @@ -/* - * attest_crypto.c - * - * Copyright (c) 2018-2019, Laurence Lundblade. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - * - * See BSD-3-Clause license in README.md - */ - -#if !defined(MBEDTLS_CONFIG_FILE) -#include "mbedtls/config.h" -#else -#include MBEDTLS_CONFIG_FILE -#endif - -#include "t_cose_crypto.h" -#include "tfm_plat_defs.h" -#include "psa/crypto.h" -#include "tfm_plat_crypto_keys.h" -#include - -#define PSA_ATTESTATION_PRIVATE_KEY_ID 17 - -/** - * \brief Context for PSA hash adaptation. - * - * Hash context for PSA hash implementation. This is fit into and cast - * to/from struct \ref t_cose_crypto_hash. - */ -struct t_cose_psa_crypto_hash { - psa_status_t status; - psa_hash_operation_t operation; -}; - -enum t_cose_err_t -t_cose_crypto_pub_key_sign(int32_t cose_alg_id, - int32_t key_select, - struct useful_buf_c hash_to_sign, - struct useful_buf signature_buffer, - struct useful_buf_c *signature) { - enum t_cose_err_t cose_ret = T_COSE_SUCCESS; - psa_status_t crypto_ret; - const size_t sig_size = t_cose_signature_size(cose_alg_id); - - (void)key_select; - - psa_key_handle_t handle; - - if (sig_size > signature_buffer.len) - { - return T_COSE_ERR_SIG_BUFFER_SIZE; - } - - crypto_ret = psa_open_key(PSA_ATTESTATION_PRIVATE_KEY_ID, &handle); - if (crypto_ret != PSA_SUCCESS) - { - return T_COSE_ERR_NO_KID; - } - - crypto_ret = psa_sign_hash(handle, - PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_256), - hash_to_sign.ptr, - hash_to_sign.len, - signature_buffer.ptr, - signature_buffer.len, - &(signature->len)); - - - if (crypto_ret != PSA_SUCCESS) - { - psa_close_key(handle); - cose_ret = T_COSE_ERR_UNSUPPORTED_SIGNING_ALG; - } else - { - signature->ptr = signature_buffer.ptr; - } - - psa_close_key(handle); - return cose_ret; -} - -enum t_cose_err_t -t_cose_crypto_get_ec_pub_key(int32_t key_select, - struct useful_buf_c kid, - int32_t *cose_curve_id, - struct useful_buf buf_to_hold_x_coord, - struct useful_buf buf_to_hold_y_coord, - struct useful_buf_c *x_coord, - struct useful_buf_c *y_coord) { - - enum tfm_plat_err_t err; - enum ecc_curve_t cose_curve; - struct ecc_key_t attest_key = {0}; - uint8_t key_buf[ECC_P_256_KEY_SIZE] = {0}; - - (void)key_select; - - /* Get the initial attestation key */ - err = tfm_plat_get_initial_attest_key(key_buf, sizeof(key_buf), - &attest_key, &cose_curve); - - /* Check the availability of the private key */ - if (err != TFM_PLAT_ERR_SUCCESS || - attest_key.pubx_key == NULL || - attest_key.puby_key == NULL) - { - return T_COSE_ERR_KEY_BUFFER_SIZE; - } - - *cose_curve_id = (int32_t)cose_curve; - - /* Check buffer size to avoid overflow */ - if (buf_to_hold_x_coord.len < attest_key.pubx_key_size) - { - return T_COSE_ERR_KEY_BUFFER_SIZE; - } - - /* Copy the X coordinate of the public key to the buffer */ - memcpy(buf_to_hold_x_coord.ptr, - (const void *)attest_key.pubx_key, - attest_key.pubx_key_size); - - /* Update size */ - buf_to_hold_x_coord.len = attest_key.pubx_key_size; - - /* Check buffer size to avoid overflow */ - if (buf_to_hold_y_coord.len < attest_key.puby_key_size) - { - return T_COSE_ERR_KEY_BUFFER_SIZE; - } - - /* Copy the Y coordinate of the public key to the buffer */ - memcpy(buf_to_hold_y_coord.ptr, - (const void *)attest_key.puby_key, - attest_key.puby_key_size); - - /* Update size */ - buf_to_hold_y_coord.len = attest_key.puby_key_size; - - x_coord->ptr = buf_to_hold_x_coord.ptr; - x_coord->len = buf_to_hold_x_coord.len; - y_coord->ptr = buf_to_hold_y_coord.ptr; - y_coord->len = buf_to_hold_y_coord.len; - - return T_COSE_SUCCESS; -} - -/** - * \brief Check some of the sizes for hash implementation. - * - * \return Value from \ref t_cose_err_t error if sizes are not correct. - * - * It makes sure the constants in the header file match the local - * implementation. This gets evaluated at compile time and will - * optimize out to nothing when all checks pass. - */ -static inline enum t_cose_err_t check_hash_sizes() -{ - if (T_COSE_CRYPTO_SHA256_SIZE != PSA_HASH_SIZE(PSA_ALG_SHA_256)) { - return T_COSE_ERR_HASH_GENERAL_FAIL; - } - - return T_COSE_SUCCESS; -} - -/** - * \brief Convert COSE algorithm ID to a PSA algorithm ID - * - * \param[in] cose_hash_alg_id The COSE-based ID for the - * - * \return PSA-based hash algorithm ID, or MD4 in the case of error. - * - */ -static inline psa_algorithm_t cose_hash_alg_id_to_psa(int32_t cose_hash_alg_id) -{ - psa_algorithm_t return_value; - - switch (cose_hash_alg_id) { - case COSE_ALG_SHA256_PROPRIETARY: - return_value = PSA_ALG_SHA_256; - break; - default: - return_value = PSA_ALG_MD4; - break; - } - - return return_value; -} - -enum t_cose_err_t -t_cose_crypto_hash_start(struct t_cose_crypto_hash *hash_ctx, - int32_t cose_hash_alg_id) { - enum t_cose_err_t cose_ret = T_COSE_SUCCESS; - psa_status_t psa_ret; - struct t_cose_psa_crypto_hash *psa_hash_ctx; - - /* These next 3 lines optimize to nothing except when there is - * failure. - */ - cose_ret = check_hash_sizes(); - if (cose_ret != T_COSE_SUCCESS) - { - return cose_ret; - } - - psa_hash_ctx = (struct t_cose_psa_crypto_hash *)hash_ctx; - memset(&psa_hash_ctx->operation, 0, sizeof(psa_hash_operation_t)); - - psa_ret = psa_hash_setup(&psa_hash_ctx->operation, - cose_hash_alg_id_to_psa(cose_hash_alg_id)); - - if (psa_ret == PSA_SUCCESS) - { - psa_hash_ctx->status = PSA_SUCCESS; - cose_ret = T_COSE_SUCCESS; - } else if (psa_ret == PSA_ERROR_NOT_SUPPORTED) - { - cose_ret = T_COSE_ERR_UNSUPPORTED_HASH; - } else - { - cose_ret = T_COSE_ERR_HASH_GENERAL_FAIL; - } - - return cose_ret; -} - -void t_cose_crypto_hash_update(struct t_cose_crypto_hash *hash_ctx, - struct useful_buf_c data_to_hash) -{ - struct t_cose_psa_crypto_hash *psa_hash_ctx; - - psa_hash_ctx = (struct t_cose_psa_crypto_hash *)hash_ctx; - - if (psa_hash_ctx->status == PSA_SUCCESS) { - if (data_to_hash.ptr != NULL) { - psa_hash_ctx->status = psa_hash_update(&psa_hash_ctx->operation, - data_to_hash.ptr, - data_to_hash.len); - } - } -} - -enum t_cose_err_t -t_cose_crypto_hash_finish(struct t_cose_crypto_hash *hash_ctx, - struct useful_buf buffer_to_hold_result, - struct useful_buf_c *hash_result) { - enum t_cose_err_t cose_ret = T_COSE_SUCCESS; - psa_status_t psa_ret; - struct t_cose_psa_crypto_hash *psa_hash_ctx; - - psa_hash_ctx = (struct t_cose_psa_crypto_hash *)hash_ctx; - - if (psa_hash_ctx->status == PSA_SUCCESS) - { - psa_ret = psa_hash_finish(&psa_hash_ctx->operation, - buffer_to_hold_result.ptr, - buffer_to_hold_result.len, - &(hash_result->len)); - - if (psa_ret == PSA_SUCCESS) { - hash_result->ptr = buffer_to_hold_result.ptr; - cose_ret = T_COSE_SUCCESS; - } else if (psa_ret == PSA_ERROR_BUFFER_TOO_SMALL) { - cose_ret = T_COSE_ERR_HASH_BUFFER_SIZE; - } else { - cose_ret = T_COSE_ERR_HASH_GENERAL_FAIL; - } - } else - { - cose_ret = T_COSE_ERR_HASH_GENERAL_FAIL; - } - - return cose_ret; -} diff --git a/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IMPL/attest_crypto_keys.c b/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IMPL/attest_crypto_keys.c deleted file mode 100755 index e67227c..0000000 --- a/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IMPL/attest_crypto_keys.c +++ /dev/null @@ -1,182 +0,0 @@ -/* -* Copyright (c) 2018-2019 ARM Limited. All rights reserved. -* -* SPDX-License-Identifier: Apache-2.0 -* -* Licensed under the Apache License, Version 2.0 (the License); you may -* not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an AS IS BASIS, WITHOUT -* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#include "tfm_plat_crypto_keys.h" -#include "psa/crypto.h" - -#include -#include - - -#define ONE_BYTE (1u) -#define PSA_ATTESTATION_PRIVATE_KEY_ID 17 - -/** - * \brief Copy the key to the destination buffer - * - * \param[out] p_dst Pointer to buffer where to store the key - * \param[in] p_src Pointer to the key - * \param[in] size Length of the key - */ -static inline void copy_key(uint8_t *p_dst, const uint8_t *p_src, size_t size) -{ - uint32_t i; - - for (i = size; i > 0; i--) { - *p_dst = *p_src; - p_src++; - p_dst++; - } -} - -static psa_status_t get_curve(psa_key_type_t type, enum ecc_curve_t *curve_type) -{ - psa_ecc_curve_t curve = PSA_KEY_TYPE_GET_CURVE(type); - switch (curve) { - case PSA_ECC_CURVE_SECP_R1: - *curve_type = P_256; - break; - case PSA_ECC_CURVE_MONTGOMERY: - *curve_type = X25519; - break; - default: - return (PSA_ERROR_NOT_SUPPORTED); - } - - return PSA_SUCCESS; -} - -enum tfm_plat_err_t -tfm_plat_get_initial_attest_key(uint8_t *key_buf, - uint32_t size, - struct ecc_key_t *ecc_key, - enum ecc_curve_t *curve_type) - -{ - uint8_t *key_dst = NULL; - uint8_t *key_src; - uint32_t key_size; - - psa_status_t crypto_ret; - - uint8_t *public_key = NULL; - psa_key_type_t type; - psa_key_type_t public_type; - psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; - size_t bits; - size_t public_key_size = 0; - size_t public_key_length = 0; - - uint32_t initial_attestation_public_x_key_size = 0; - uint32_t initial_attestation_public_y_key_size = 0; - - psa_key_handle_t handle; - - crypto_ret = psa_open_key(PSA_ATTESTATION_PRIVATE_KEY_ID, &handle); - if (crypto_ret != PSA_SUCCESS) - { - return TFM_PLAT_ERR_SYSTEM_ERR; - } - - crypto_ret = psa_get_key_attributes(handle, &attributes); - if (crypto_ret != PSA_SUCCESS) - { - psa_close_key(handle); - return TFM_PLAT_ERR_SYSTEM_ERR; - } - type = psa_get_key_type(&attributes); - if (!PSA_KEY_TYPE_IS_ECC(type)) - { - psa_close_key(handle); - return TFM_PLAT_ERR_SYSTEM_ERR; - } - public_type = PSA_KEY_TYPE_PUBLIC_KEY_OF_KEY_PAIR(type); - bits = psa_get_key_bits(&attributes); - public_key_size = PSA_KEY_EXPORT_MAX_SIZE(public_type, bits); - public_key = (uint8_t *) malloc(public_key_size); - if (public_key == NULL) - { - psa_close_key(handle); - return TFM_PLAT_ERR_SYSTEM_ERR; - } - - crypto_ret = psa_export_public_key(handle, - public_key, public_key_size, - &public_key_length); - if (crypto_ret != PSA_SUCCESS) - { - free(public_key); - psa_close_key(handle); - return TFM_PLAT_ERR_SYSTEM_ERR; - } - - /* Set the EC curve type which the key belongs to */ - crypto_ret = get_curve(type, curve_type); - if (crypto_ret != PSA_SUCCESS) - { - free(public_key); - psa_close_key(handle); - return TFM_PLAT_ERR_SYSTEM_ERR; - } - - key_src = public_key; - key_dst = key_buf; - - /* The representation of an ECC public key is: - ** -The byte 0x04 - ** - `x_P` as a `ceiling(m/8)`-byte string, big-endian - ** - `y_P` as a `ceiling(m/8)`-byte string, big-endian - ** - where m is the bit size associated with the curve - ** - 1 byte + 2 * point size - */ - initial_attestation_public_x_key_size = ceil((public_key_length - 1) / 2); - initial_attestation_public_y_key_size = ceil((public_key_length - 1) / 2); - - /* Copy the x-coordinate of public key to the buffer */ - if (initial_attestation_public_x_key_size != 0) - { - key_src = key_src + ONE_BYTE; - key_size = initial_attestation_public_x_key_size; - copy_key(key_dst, key_src, key_size); - ecc_key->pubx_key = key_dst; - ecc_key->pubx_key_size = key_size; - key_dst = key_dst + key_size; - } else - { - ecc_key->pubx_key = NULL; - ecc_key->pubx_key_size = 0; - } - - /* Copy the y-coordinate of public key to the buffer */ - if (initial_attestation_public_y_key_size != 0) - { - key_src += initial_attestation_public_x_key_size; - key_size = initial_attestation_public_y_key_size; - copy_key(key_dst, key_src, key_size); - ecc_key->puby_key = key_dst; - ecc_key->puby_key_size = key_size; - } else - { - ecc_key->puby_key = NULL; - ecc_key->puby_key_size = 0; - } - - free(public_key); - psa_close_key(handle); - return TFM_PLAT_ERR_SUCCESS; -} diff --git a/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IMPL/attest_iat_claims_loader.c b/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IMPL/attest_iat_claims_loader.c deleted file mode 100755 index 8cae245..0000000 --- a/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IMPL/attest_iat_claims_loader.c +++ /dev/null @@ -1,222 +0,0 @@ -/* -* Copyright (c) 2018-2019 ARM Limited. All rights reserved. -* -* SPDX-License-Identifier: Apache-2.0 -* -* Licensed under the Apache License, Version 2.0 (the License); you may -* not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an AS IS BASIS, WITHOUT -* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#include -#include -#include -#include -#include "tfm_plat_boot_seed.h" -#include "attestation_bootloader_data.h" -#include "tfm_attest_hal.h" -#include "psa_initial_attestation_api.h" -#include "attestation.h" -#include "psa/crypto.h" -#include "psa/lifecycle.h" - -extern int32_t g_caller_id; - -#define ATTEST_PUB_KEY_SHA_256_SIZE (32u) -#define PSA_ATTESTATION_PRIVATE_KEY_ID 17 - -static enum tfm_security_lifecycle_t security_lifecycle_psa_to_tfm(void) -{ - uint32_t lc = psa_security_lifecycle_state(); - switch (lc) { - case PSA_LIFECYCLE_UNKNOWN: - return TFM_SLC_UNKNOWN; - case PSA_LIFECYCLE_ASSEMBLY_AND_TEST: - return TFM_SLC_ASSEMBLY_AND_TEST; - case PSA_LIFECYCLE_PSA_ROT_PROVISIONING: - return TFM_SLC_PSA_ROT_PROVISIONING; - case PSA_LIFECYCLE_SECURED: - return TFM_SLC_SECURED; - case PSA_LIFECYCLE_NON_PSA_ROT_DEBUG: - return TFM_SLC_NON_PSA_ROT_DEBUG; - case PSA_LIFECYCLE_RECOVERABLE_PSA_ROT_DEBUG: - return TFM_SLC_RECOVERABLE_PSA_ROT_DEBUG; - case PSA_LIFECYCLE_DECOMMISSIONED: - return TFM_SLC_DECOMMISSIONED; - default: - return TFM_SLC_UNKNOWN; - } -} - -/* Hash of attestation public key */ -static enum tfm_plat_err_t attest_public_key_sha256(uint32_t *size, uint8_t *buf) -{ - psa_key_handle_t handle = 0; - - uint8_t *public_key = NULL; - psa_key_type_t type; - psa_key_type_t public_type; - psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; - size_t bits; - size_t public_key_size = 0; - size_t public_key_length = 0; - - psa_status_t crypto_ret; - enum tfm_plat_err_t status = TFM_PLAT_ERR_SUCCESS; - psa_hash_operation_t hash_handle = {0}; - - crypto_ret = psa_open_key(PSA_ATTESTATION_PRIVATE_KEY_ID, &handle); - if (crypto_ret != PSA_SUCCESS) { - return TFM_PLAT_ERR_SYSTEM_ERR; - } - - crypto_ret = psa_get_key_attributes(handle, &attributes); - if (crypto_ret != PSA_SUCCESS) { - status = TFM_PLAT_ERR_SYSTEM_ERR; - goto exit; - } - type = psa_get_key_type(&attributes); - if (!PSA_KEY_TYPE_IS_ECC(type)) { - status = TFM_PLAT_ERR_SYSTEM_ERR; - goto exit; - } - public_type = PSA_KEY_TYPE_PUBLIC_KEY_OF_KEY_PAIR(type); - bits = psa_get_key_bits(&attributes); - public_key_size = PSA_KEY_EXPORT_MAX_SIZE(public_type, bits); - public_key = (uint8_t *) malloc(public_key_size); - if (public_key == NULL) { - status = TFM_PLAT_ERR_SYSTEM_ERR; - goto exit; - } - - crypto_ret = psa_export_public_key(handle, - public_key, public_key_size, - &public_key_length); - if (crypto_ret != PSA_SUCCESS) { - status = TFM_PLAT_ERR_SYSTEM_ERR; - goto exit; - } - - crypto_ret = psa_hash_setup(&hash_handle, PSA_ALG_SHA_256); - if (crypto_ret != PSA_SUCCESS) { - status = TFM_PLAT_ERR_SYSTEM_ERR; - goto exit; - } - - psa_hash_update(&hash_handle, public_key, public_key_length); - - crypto_ret = psa_hash_finish(&hash_handle, - buf, - ATTEST_PUB_KEY_SHA_256_SIZE, - (size_t *) size); - if (crypto_ret != PSA_SUCCESS) { - status = TFM_PLAT_ERR_SYSTEM_ERR; - goto exit; - } - -exit: - if (public_key != NULL) { - free(public_key); - } - psa_close_key(handle); - return status; -} - -/** - * \brief Copy the device specific ID to the destination buffer - * - * \param[out] p_dst Pointer to buffer where to store ID - * \param[in] p_src Pointer to the ID - * \param[in] size Length of the ID - */ -static inline void copy_id(uint8_t *p_dst, uint8_t *p_src, size_t size) -{ - uint32_t i; - - for (i = size; i > 0; i--) { - *p_dst = *p_src; - p_src++; - p_dst++; - } -} - -enum psa_attest_err_t attest_get_caller_client_id(int32_t *caller_id) -{ - *caller_id = g_caller_id; - return PSA_ATTEST_ERR_SUCCESS; -} - -/* Boot seed data is part of bootloader status*/ -enum tfm_plat_err_t tfm_plat_get_boot_seed(uint32_t size, uint8_t *buf) -{ - return (enum tfm_plat_err_t)PSA_ATTEST_ERR_CLAIM_UNAVAILABLE; -} - -/** - * Instance ID is mapped to EAT Universal Entity ID (UEID) - * This implementation creates the instance ID as follows: - * - byte 0: 0x01 indicates the type of UEID to be GUID - * - byte 1-32: Hash of attestation public key. Public key is hashed in raw - * format without any encoding. - */ -enum tfm_plat_err_t tfm_plat_get_instance_id(uint32_t *size, uint8_t *buf) -{ - enum tfm_plat_err_t status; - - buf[0] = 0x01; /* First byte is type byte: 0x01 indicates GUID */ - - status = attest_public_key_sha256(size, &buf[1]); - - /* Instance ID size: 1 type byte + size of public key hash */ - *size = *size + 1; - - return status; -} - -/* HW version data is part of bootloader status*/ -enum tfm_plat_err_t tfm_plat_get_hw_version(uint32_t *size, uint8_t *buf) -{ - return (enum tfm_plat_err_t)PSA_ATTEST_ERR_CLAIM_UNAVAILABLE; -} - -enum tfm_plat_err_t tfm_plat_get_implementation_id(uint32_t *size, uint8_t *buf) -{ - memcpy(buf, impl_id_data, *size); - return (enum tfm_plat_err_t)PSA_ATTEST_ERR_SUCCESS; -} - -/* Temporary Implementation of security lifecycle data: mandatory claim. -** tfm_attest_hal_get_security_lifecycle function should return -** 'PSA_ATTEST_ERR_CLAIM_UNAVAILABLE' if been called. -** Security lifecycle data is part of bootloader status data. -** Temp implementation of using psa_security_lifecycle_state */ - -enum tfm_security_lifecycle_t tfm_attest_hal_get_security_lifecycle(void) -{ - return security_lifecycle_psa_to_tfm(); -} - - -const char * -tfm_attest_hal_get_verification_service(uint32_t *size) -{ - *size = sizeof(verification_service_url) - 1; - return verification_service_url; -} - -const char * -tfm_attest_hal_get_profile_definition(uint32_t *size) -{ - *size = sizeof(attestation_profile_definition) - 1; - return attestation_profile_definition; -} - - diff --git a/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IMPL/attestation_bootloader_data.c b/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IMPL/attestation_bootloader_data.c deleted file mode 100755 index 797ecea..0000000 --- a/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IMPL/attestation_bootloader_data.c +++ /dev/null @@ -1,64 +0,0 @@ -/* -* Copyright (c) 2018-2019 ARM Limited. All rights reserved. -* -* SPDX-License-Identifier: Apache-2.0 -* -* Licensed under the Apache License, Version 2.0 (the License); you may -* not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an AS IS BASIS, WITHOUT -* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#include "attestation_bootloader_data.h" - -/* Temporary Boodloader data - contains temp mandatory claims */ -__attribute__((aligned(4))) -const uint8_t temp_ram_page_data[] = { - 0x16, 0x20, 0xAC, 0x00, //shared_data_tlv_header - 0x83, 0x11, 0x0C, 0x00, // SW_TYPE - 0x4E, 0x53, 0x50, 0x45, 0x5F, 0x53, 0x50, 0x45, - 0x80, 0x11, 0x0A, 0x00, //SW_VERSION - 0x31, 0x2E, 0x31, 0x2E, 0x31, 0x31, - 0x82, 0x11, 0x06, 0x00, //SW_EPOCH - 0x00, 0x00, - 0x88, 0x11, 0x24, 0x00, //SW_MEASURE_VALUE - 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, - 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, - 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, - 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, - 0x81, 0x11, 0x24, 0x00, //SW_SIGNER_ID - 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, - 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, - 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, - 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, - 0x89, 0x11, 0x0A, 0x00, //SW_MEASURE_TYPE - 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, - 0x00, 0x10, 0x24, 0x00, //TLV_MINOR_IAS_BOOT_SEED - 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, - 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, - 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, - 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, - 0x01, 0x10, 0x16, 0x00, //TLV_MINOR_IAS_HW_VERSION - 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, - 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, - 0x31, 0x32 -}; - -/* Temporary Implementation ID data: mandatory claim represents the original -** implementation signer of the attestation key and identifies the contract -** between the report and verification */ -#define TEMP_IMPL_ID_DATA_SIZE (32u) - -#define TEMP_IMPL_ID_DATA 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, \ - 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, \ - 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, \ - 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF - -const uint8_t impl_id_data[TEMP_IMPL_ID_DATA_SIZE] = {TEMP_IMPL_ID_DATA}; diff --git a/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IMPL/attestation_bootloader_data.h b/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IMPL/attestation_bootloader_data.h deleted file mode 100755 index 6f0c560..0000000 --- a/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IMPL/attestation_bootloader_data.h +++ /dev/null @@ -1,48 +0,0 @@ -/* -* Copyright (c) 2018-2019 ARM Limited. All rights reserved. -* -* SPDX-License-Identifier: Apache-2.0 -* -* Licensed under the Apache License, Version 2.0 (the License); you may -* not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an AS IS BASIS, WITHOUT -* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#ifndef __ATTESTATION_BOOTLOADER_DATA_H__ -#define __ATTESTATION_BOOTLOADER_DATA_H__ - -#include -#include - - -#ifdef __cplusplus -extern "C" { -#endif - -/* Temp Shared data area between bootloader and runtime firmware */ -extern const uint8_t temp_ram_page_data[]; - -#define S_RAM_ALIAS_BASE (temp_ram_page_data) - -#define BOOT_TFM_SHARED_DATA_BASE S_RAM_ALIAS_BASE - -extern const uint8_t impl_id_data[]; - -/* Example verification service URL for initial attestation token - temporary data*/ -static const char verification_service_url[] = "www.mbed.com"; -/* Example profile definition document for initial attestation token - temporary data*/ -static const char attestation_profile_definition[] = "psa-attest.md"; - -#ifdef __cplusplus -} -#endif - -#endif /* __ATTESTATION_BOOTLOADER_DATA_H__ */ diff --git a/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IMPL/psa_attestation_stubs.c b/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IMPL/psa_attestation_stubs.c deleted file mode 100755 index b36c64a..0000000 --- a/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IMPL/psa_attestation_stubs.c +++ /dev/null @@ -1,31 +0,0 @@ -/* -* Copyright (c) 2018-2019 ARM Limited. All rights reserved. -* -* SPDX-License-Identifier: Apache-2.0 -* -* Licensed under the Apache License, Version 2.0 (the License); you may -* not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an AS IS BASIS, WITHOUT -* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#include -#include "attestation.h" - -enum psa_attest_err_t -attest_check_memory_access(void *addr, - uint32_t size, - enum attest_memory_access_t access) { - if (size == 0) - { - return PSA_ATTEST_ERR_INVALID_INPUT; - } - return PSA_ATTEST_ERR_SUCCESS; -} diff --git a/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IMPL/psa_inject_attestation_key_impl.c b/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IMPL/psa_inject_attestation_key_impl.c deleted file mode 100755 index c63d93e..0000000 --- a/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IMPL/psa_inject_attestation_key_impl.c +++ /dev/null @@ -1,108 +0,0 @@ -/* -* Copyright (c) 2018-2019 ARM Limited. All rights reserved. -* -* SPDX-License-Identifier: Apache-2.0 -* -* Licensed under the Apache License, Version 2.0 (the License); you may -* not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an AS IS BASIS, WITHOUT -* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ -#include "psa_inject_attestation_key_impl.h" - -#define ECDSA_P256_KEY_SIZE_IN_BYTES 32 -#define PSA_ATTESTATION_PRIVATE_KEY_ID 17 - -psa_status_t -psa_attestation_inject_key_impl(const uint8_t *key_data, - size_t key_data_length, - psa_key_type_t type, - uint8_t *public_key_data, - size_t public_key_data_size, - size_t *public_key_data_length) -{ - psa_status_t status = PSA_SUCCESS; - size_t key_data_bits = ECDSA_P256_KEY_SIZE_IN_BYTES * 8; - psa_key_handle_t handle = 0; - psa_key_id_t key_id = PSA_ATTESTATION_PRIVATE_KEY_ID; - psa_key_lifetime_t lifetime = PSA_KEY_LIFETIME_PERSISTENT; - psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; - psa_key_usage_t usage = PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_SIGN | PSA_KEY_USAGE_VERIFY; - psa_key_type_t public_type; - size_t bits; - size_t exported_size = 0; - psa_key_type_t type_key; - -#if defined(MBEDTLS_ECP_C) - - status = psa_open_key(key_id, &handle); - if (status == PSA_SUCCESS) { - /* The key already has been injected */ - goto exit; - } - - psa_set_key_usage_flags(&attributes, usage); - psa_set_key_algorithm(&attributes, PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_256)); - psa_set_key_type(&attributes, type); - psa_set_key_bits(&attributes, key_data_bits); - psa_set_key_lifetime(&attributes, lifetime); - psa_set_key_id(&attributes, key_id); - - if (! PSA_KEY_TYPE_IS_ECC_KEY_PAIR(type)) { - return (PSA_ERROR_INVALID_ARGUMENT); - } - - if (key_data != NULL) { - if (key_data_length != ECDSA_P256_KEY_SIZE_IN_BYTES) { - status = PSA_ERROR_INVALID_ARGUMENT; - goto exit; - } - status = psa_import_key(&attributes, key_data, key_data_length, &handle); - if (status != PSA_SUCCESS) { - goto exit; - } - } else { - /* generating key pair */ - key_data_bits = ECDSA_P256_KEY_SIZE_IN_BYTES * 8; - status = psa_generate_key(&attributes, &handle); - if (status != PSA_SUCCESS) { - goto exit; - } - } - - status = psa_get_key_attributes(handle, &attributes); - if (status != PSA_SUCCESS) { - goto exit; - } - - type_key = psa_get_key_type(&attributes); - public_type = PSA_KEY_TYPE_PUBLIC_KEY_OF_KEY_PAIR(type_key); - bits = psa_get_key_bits(&attributes); - exported_size = PSA_KEY_EXPORT_MAX_SIZE(public_type, bits); - - status = psa_export_public_key(handle, - public_key_data, - public_key_data_size, - public_key_data_length); - if (status != PSA_SUCCESS) { - goto exit; - } - if (*public_key_data_length > exported_size) { - status = PSA_ERROR_INVALID_ARGUMENT; - goto exit; - } - -exit: - psa_close_key(handle); - return (status); -#endif /* MBEDTLS_ECP_C */ - - return (PSA_ERROR_NOT_SUPPORTED); -} diff --git a/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IMPL/psa_inject_attestation_key_impl.h b/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IMPL/psa_inject_attestation_key_impl.h deleted file mode 100755 index de6e1bb..0000000 --- a/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IMPL/psa_inject_attestation_key_impl.h +++ /dev/null @@ -1,43 +0,0 @@ -/* -* Copyright (c) 2018-2019 ARM Limited. All rights reserved. -* -* SPDX-License-Identifier: Apache-2.0 -* -* Licensed under the Apache License, Version 2.0 (the License); you may -* not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an AS IS BASIS, WITHOUT -* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#ifndef __PSA_INITIAL_ATTESTATION_IMPL_H__ -#define __PSA_INITIAL_ATTESTATION_IMPL_H__ - -#include "psa/crypto.h" -#include -#include - -#ifdef __cplusplus -extern "C" -{ -#endif - -psa_status_t -psa_attestation_inject_key_impl(const uint8_t *key_data, - size_t key_data_length, - psa_key_type_t type, - uint8_t *public_key_data, - size_t public_key_data_size, - size_t *public_key_data_length); - -#ifdef __cplusplus -} -#endif - -#endif /* __PSA_INITIAL_ATTESTATION_IMPL_H__ */ diff --git a/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/attest_eat_defines.h b/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/attest_eat_defines.h deleted file mode 100755 index 002e2a1..0000000 --- a/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/attest_eat_defines.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2019, Arm Limited. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - * - */ - -#ifndef __ATTEST_EAT_DEFINES_H__ -#define __ATTEST_EAT_DEFINES_H__ - -#ifdef __cplusplus -extern "C" { -#endif - -#define EAT_CBOR_ARM_RANGE_BASE (-75000) -#define EAT_CBOR_ARM_LABEL_PROFILE_DEFINITION (EAT_CBOR_ARM_RANGE_BASE - 0) -#define EAT_CBOR_ARM_LABEL_CLIENT_ID (EAT_CBOR_ARM_RANGE_BASE - 1) -#define EAT_CBOR_ARM_LABEL_SECURITY_LIFECYCLE (EAT_CBOR_ARM_RANGE_BASE - 2) -#define EAT_CBOR_ARM_LABEL_IMPLEMENTATION_ID (EAT_CBOR_ARM_RANGE_BASE - 3) -#define EAT_CBOR_ARM_LABEL_BOOT_SEED (EAT_CBOR_ARM_RANGE_BASE - 4) -#define EAT_CBOR_ARM_LABEL_HW_VERSION (EAT_CBOR_ARM_RANGE_BASE - 5) -#define EAT_CBOR_ARM_LABEL_SW_COMPONENTS (EAT_CBOR_ARM_RANGE_BASE - 6) -#define EAT_CBOR_ARM_LABEL_NO_SW_COMPONENTS (EAT_CBOR_ARM_RANGE_BASE - 7) -#define EAT_CBOR_ARM_LABEL_CHALLENGE (EAT_CBOR_ARM_RANGE_BASE - 8) -#define EAT_CBOR_ARM_LABEL_UEID (EAT_CBOR_ARM_RANGE_BASE - 9) -#define EAT_CBOR_ARM_LABEL_ORIGINATION (EAT_CBOR_ARM_RANGE_BASE - 10) - -#define EAT_CBOR_SW_COMPONENT_MEASUREMENT_TYPE (1) -#define EAT_CBOR_SW_COMPONENT_MEASUREMENT_VALUE (2) -#define EAT_CBOR_SW_COMPONENT_SECURITY_EPOCH (3) -#define EAT_CBOR_SW_COMPONENT_VERSION (4) -#define EAT_CBOR_SW_COMPONENT_SIGNER_ID (5) -#define EAT_CBOR_SW_COMPONENT_MEASUREMENT_DESC (6) - -#ifdef __cplusplus -} -#endif - -#endif /* __ATTEST_EAT_DEFINES_H__ */ diff --git a/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/attest_token.c b/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/attest_token.c deleted file mode 100755 index 8cf5f74..0000000 --- a/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/attest_token.c +++ /dev/null @@ -1,228 +0,0 @@ -/* - * attest_token.c - * - * Copyright (c) 2018-2019, Laurence Lundblade. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - * - * See BSD-3-Clause license in README.md - */ - -#include "attest_token.h" -#include "qcbor.h" -#include "t_cose_sign1_sign.h" - - -/** - * \file attest_token.c - * - * \brief Attestation token creation implementation - * - * Outline of token creation. Much of this occurs inside - * t_cose_sign1_init() and t_cose_sign1_finish(). - * - * - Create encoder context - * - Open the CBOR array that hold the \c COSE_Sign1 - * - Write COSE Headers - * - Protected Header - * - Algorithm ID - * - Unprotected Headers - * - Key ID - * - Open payload bstr - * - Write payload data… lots of it… - * - Get bstr that is the encoded payload - * - Compute signature - * - Create a separate encoder context for \c Sig_structure - * - Encode CBOR context identifier - * - Encode protected headers - * - Encode two empty bstr - * - Add one more empty bstr that is a "fake payload" - * - Close off \c Sig_structure - * - Hash all but "fake payload" of \c Sig_structure - * - Get payload bstr ptr and length - * - Continue hash of the real encoded payload - * - Run ECDSA - * - Write signature into the CBOR output - * - Close CBOR array holding the \c COSE_Sign1 - */ - -/* - * \brief Map t_cose error to attestation token error. - * - * \param[in] err The t_cose error to map. - * - * \return the attestation token error. - * - */ -static enum attest_token_err_t t_cose_err_to_attest_err(enum t_cose_err_t err) -{ - switch(err) { - - case T_COSE_SUCCESS: - return ATTEST_TOKEN_ERR_SUCCESS; - - case T_COSE_ERR_UNSUPPORTED_HASH: - return ATTEST_TOKEN_ERR_HASH_UNAVAILABLE; - - default: - /* A lot of the errors are not mapped because they are - * primarily internal errors that should never happen. They - * end up here. - */ - return ATTEST_TOKEN_ERR_GENERAL; - } -} - - -/* - Public function. See attest_token.h - */ -enum attest_token_err_t attest_token_start(struct attest_token_ctx *me, - uint32_t opt_flags, - int32_t key_select, - int32_t cose_alg_id, - const struct useful_buf *out_buf) -{ - /* approximate stack usage on 32-bit machine: 4 bytes */ - enum t_cose_err_t cose_return_value; - enum attest_token_err_t return_value; - - /* Remember some of the configuration values */ - me->opt_flags = opt_flags; - me->key_select = key_select; - - /* Spin up the CBOR encoder */ - QCBOREncode_Init(&(me->cbor_enc_ctx), *out_buf); - - - /* Initialize COSE signer. This will cause the cose headers to be - * encoded and written into out_buf using me->cbor_enc_ctx - */ - cose_return_value = t_cose_sign1_init(&(me->signer_ctx), - opt_flags & - TOKEN_OPT_SHORT_CIRCUIT_SIGN, - cose_alg_id, - key_select, - &(me->cbor_enc_ctx)); - if(cose_return_value) { - return_value = t_cose_err_to_attest_err(cose_return_value); - goto Done; - } - - /* Open the payload-wrapping bstr */ - QCBOREncode_BstrWrap(&(me->cbor_enc_ctx)); - - QCBOREncode_OpenMap(&(me->cbor_enc_ctx)); - - return_value = ATTEST_TOKEN_ERR_SUCCESS; - -Done: - return return_value; -} - - -/* - Public function. See attest_token.h - */ -QCBOREncodeContext *attest_token_borrow_cbor_cntxt(struct attest_token_ctx *me) -{ - return &(me->cbor_enc_ctx); -} - - -/* - Public function. See attest_token.h - */ -void attest_token_add_integer(struct attest_token_ctx *me, - int32_t label, - int64_t Value) -{ - QCBOREncode_AddInt64ToMapN(&(me->cbor_enc_ctx), label, Value); -} - - -/* - Public function. See attest_token.h - */ -void attest_token_add_bstr(struct attest_token_ctx *me, - int32_t label, - const struct useful_buf_c *bstr) -{ - QCBOREncode_AddBytesToMapN(&(me->cbor_enc_ctx), - label, - *bstr); -} - - -/* - Public function. See attest_token.h - */ -void attest_token_add_tstr(struct attest_token_ctx *me, - int32_t label, - const struct useful_buf_c *tstr) -{ - QCBOREncode_AddTextToMapN(&(me->cbor_enc_ctx), label, *tstr); -} - - -/* - See attest_token.h - */ -void attest_token_add_encoded(struct attest_token_ctx *me, - int32_t label, - const struct useful_buf_c *encoded) -{ - QCBOREncode_AddEncodedToMapN(&(me->cbor_enc_ctx), label, *encoded); -} - - -/* - Public function. See attest_token.h - */ -enum attest_token_err_t -attest_token_finish(struct attest_token_ctx *me, - struct useful_buf_c *completed_token) -{ - /* approximate stack usage on 32-bit machine: 4 + 4 + 8 + 8 = 24 */ - enum attest_token_err_t return_value = ATTEST_TOKEN_ERR_SUCCESS; - /* The payload with all the claims that is signed */ - struct useful_buf_c token_payload_ub; - /* The completed and signed encoded cose_sign1 */ - struct useful_buf_c completed_token_ub; - QCBORError qcbor_result; - enum t_cose_err_t cose_return_value; - - QCBOREncode_CloseMap(&(me->cbor_enc_ctx)); - - /* Close off the payload-wrapping bstr. This gives us back the - * pointer and length of the payload that needs to be hashed as - * part of the signature - */ - QCBOREncode_CloseBstrWrap(&(me->cbor_enc_ctx), &token_payload_ub); - - /* Finish off the cose signature. This does all the interesting work of - hashing and signing */ - cose_return_value = - t_cose_sign1_finish(&(me->signer_ctx), token_payload_ub); - if(cose_return_value) { - /* Main errors are invoking the hash or signature */ - return_value = t_cose_err_to_attest_err(cose_return_value); - goto Done; - } - - /* Close off the CBOR encoding and return the completed token */ - qcbor_result = QCBOREncode_Finish(&(me->cbor_enc_ctx), - &completed_token_ub); - if(qcbor_result == QCBOR_ERR_BUFFER_TOO_SMALL) { - return_value = ATTEST_TOKEN_ERR_TOO_SMALL; - } else if (qcbor_result != QCBOR_SUCCESS) { - /* likely from array not closed, too many closes, ... */ - return_value = ATTEST_TOKEN_ERR_CBOR_FORMATTING; - } else { - *completed_token = completed_token_ub; - } - -Done: - return return_value; -} - diff --git a/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/attest_token.h b/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/attest_token.h deleted file mode 100755 index 903c42b..0000000 --- a/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/attest_token.h +++ /dev/null @@ -1,241 +0,0 @@ -/* - * attest_token.h - * - * Copyright (c) 2018-2019, Laurence Lundblade. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - * - * See BSD-3-Clause license in README.md - */ - -#ifndef __ATTEST_TOKEN_H__ -#define __ATTEST_TOKEN_H__ - -#include -#include "qcbor.h" -#include "t_cose_sign1_sign.h" - - -/** - * \file attest_token.h - * - * \brief Attestation Token Creation Interface - * - * The context and functions here are the way to create an attestation - * token. The steps are roughly: - * - * -# Creation and initialize an attest_token_ctx indicating the - * options, key and such using attest_token_start(). - * - * -# Use various add methods to fill in the payload with claims. The - * encoding context can also be borrowed for more rich payloads. - * - * -# Call attest_token_finish() to create the signature and finish - * formatting the COSE signed output. - */ - - -/** - Error codes returned from attestation token creation. - */ -enum attest_token_err_t { - /** Success */ - ATTEST_TOKEN_ERR_SUCCESS = 0, - /** The buffer passed in to receive the output is too small. */ - ATTEST_TOKEN_ERR_TOO_SMALL, - /** Something went wrong formatting the CBOR, most likely the - payload has maps or arrays that are not closed. */ - ATTEST_TOKEN_ERR_CBOR_FORMATTING, - /** A general, unspecific error when creating or decoding the - token. */ - ATTEST_TOKEN_ERR_GENERAL, - /** A hash function that is needed to make the token is not - available. */ - ATTEST_TOKEN_ERR_HASH_UNAVAILABLE, - /** CBOR Syntax not well-formed -- a CBOR syntax error. */ - ATTEST_TOKEN_ERR_CBOR_NOT_WELL_FORMED, - /** Bad CBOR structure, for example not a map when was is - required. */ - ATTEST_TOKEN_ERR_CBOR_STRUCTURE, - /** Bad CBOR type, for example an not a text string, when a text - string is required. */ - ATTETST_TOKEN_ERR_CBOR_TYPE, - /** Integer too large, for example an \c int32_t is required, but - value only fits in \c int64_t */ - ATTEST_TOKEN_ERR_INTEGER_VALUE, - /** Something is wrong with the COSE signing structure, missing - headers or such. */ - ATTEST_TOKEN_ERR_COSE_SIGN1_FORMAT, - /** COSE signature is invalid, data is corrupted. */ - ATTEST_TOKEN_ERR_COSE_SIGN1_VALIDATION, - /** The signing algorithm is not supported. */ - ATTEST_TOKEN_ERR_UNSUPPORTED_SIG_ALG, - /** Out of memory. */ - ATTEST_TOKEN_ERR_INSUFFICIENT_MEMORY, - /** Tampering detected in cryptographic function. */ - ATTEST_TOKEN_ERR_TAMPERING_DETECTED, - /** Verification key is not found or of wrong type. */ - ATTEST_TOKEN_ERR_VERIFICATION_KEY -}; - - - -/** - * Request that the claims internally generated not be added to the - * token. This is a test mode that results in a static token that - * never changes. Only the nonce is included. The nonce is under - * the callers control unlike the other claims. - */ -#define TOKEN_OPT_OMIT_CLAIMS 0x40000000 - - -/** - * A special test mode where a proper signature is not produced. In - * its place there is a concatenation of hashes of the payload to be - * the same size as the signature. This works and can be used to - * verify all of the SW stack except the public signature part. The - * token has no security value in this mode because anyone can - * replicate it. */ -#define TOKEN_OPT_SHORT_CIRCUIT_SIGN 0x80000000 - - -/** - * The context for creating an attestation token. The caller of - * attest_token must create one of these and pass it to the functions - * here. It is small enough that it can go on the stack. It is most of - * the memory needed to create a token except the output buffer and - * any memory requirements for the cryptographic operations. - * - * The structure is opaque for the caller. - * - * This is roughly 148 + 8 + 32 = 188 bytes - */ -struct attest_token_ctx { - /* Private data structure */ - QCBOREncodeContext cbor_enc_ctx; - uint32_t opt_flags; - int32_t key_select; - struct t_cose_sign1_ctx signer_ctx; -}; - - -/** - * \brief Initialize a token creation context. - * - * \param[in] me The token creation context to be initialized. - * \param[in] opt_flags Flags to select different custom options, - for example \ref TOKEN_OPT_OMIT_CLAIMS. - * \param[in] key_select Selects which attestation key to sign with. - * \param[in] cose_alg_id The algorithm to sign with. The IDs are - * defined in [COSE (RFC 8152)] - * (https://tools.ietf.org/html/rfc8152) or - * in the [IANA COSE Registry] - * (https://www.iana.org/assignments/cose/cose.xhtml). - * \param[out] out_buffer The output buffer to write the encoded token into. - * - * \return one of the \ref attest_token_err_t errors. - * - * The size of the buffer in \c out_buffer->len - * determines the size of the token that can be created. It must be - * able to hold the final encoded and signed token. The data encoding - * overhead is just that of CBOR. The signing overhead depends on the - * signing key size. It is about 150 bytes for 256-bit ECDSA. - * - * If \c out_buffer->ptr is \c NULL and \c out_buffer_ptr->len is - * large like \c UINT32_MAX no token will be created but the length of - * the token that would be created will be in \c completed_token as - * returned by attest_token_finish(). None of the cryptographic - * functions run during this, but the sizes of what they would output - * is taken into account. - */ -enum attest_token_err_t -attest_token_start(struct attest_token_ctx *me, - uint32_t opt_flags, - int32_t key_select, - int32_t cose_alg_id, - const struct useful_buf *out_buffer); - - - -/** - * \brief Get a copy of the CBOR encoding context - * - * \param[in] me Token creation context. - * - * \return The CBOR encoding context - * - * Allows the caller to encode CBOR right into the output buffer using - * any of the \c QCBOREncode_AddXXXX() methods. Anything added here - * will be part of the payload that gets hashed. This can be used to - * make complex CBOR structures. All open arrays and maps must be - * close before calling any other \c attest_token methods. \c - * QCBOREncode_Finish() should not be closed on this context. - */ -QCBOREncodeContext *attest_token_borrow_cbor_cntxt(struct attest_token_ctx *me); - -/** - * \brief Add a 64-bit signed integer claim - * - * \param[in] me Token creation context. - * \param[in] label Integer label for claim. - * \param[in] value The integer claim data. - */ -void attest_token_add_integer(struct attest_token_ctx *me, - int32_t label, - int64_t value); - -/** - * \brief Add a binary string claim - * - * \param[in] me Token creation context. - * \param[in] label Integer label for claim. - * \param[in] value The binary claim data. - */ -void attest_token_add_bstr(struct attest_token_ctx *me, - int32_t label, - const struct useful_buf_c *value); - -/** - * \brief Add a text string claim - * - * \param[in] me Token creation context. - * \param[in] label Integer label for claim. - * \param[in] value The text claim data. - */ -void attest_token_add_tstr(struct attest_token_ctx *me, - int32_t label, - const struct useful_buf_c *value); - -/** - * \brief Add some already-encoded CBOR to payload - * - * \param[in] me Token creation context. - * \param[in] label Integer label for claim. - * \param[in] encoded The already-encoded CBOR. - * - * Encoded CBOR must be a full map or full array or a non-aggregate - * type. It cannot be a partial map or array. It can be nested maps - * and arrays, but they must all be complete. - */ -void attest_token_add_encoded(struct attest_token_ctx *me, - int32_t label, - const struct useful_buf_c *encoded); - - -/** - * \brief Finish the token, complete the signing and get the result - * - * \param[in] me Token Creation Context. - * \param[out] completed_token Pointer and length to completed token. - * - * \return one of the \ref attest_token_err_t errors. - * - * This completes the token after the payload has been added. When - * this is called the signing algorithm is run and the final - * formatting of the token is completed. - */ -enum attest_token_err_t -attest_token_finish(struct attest_token_ctx *me, - struct useful_buf_c *completed_token); - -#endif /* __ATTEST_TOKEN_H__ */ diff --git a/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/attestation_core.c b/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/attestation_core.c deleted file mode 100755 index a7e46da..0000000 --- a/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/attestation_core.c +++ /dev/null @@ -1,1032 +0,0 @@ -/* - * Copyright (c) 2018-2019, Arm Limited. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - * - */ - -#include -#include -#include -#include "tfm_client.h" -#include "attestation.h" -#include "tfm_impl/tfm_boot_status.h" -#include "tfm_plat_defs.h" -#include "tfm_plat_device_id.h" -#include "tfm_plat_boot_seed.h" -#include "tfm_attest_hal.h" -#include "attest_token.h" -#include "attest_eat_defines.h" -#include "t_cose_defines.h" -#include "tfm_memory_utils.h" - -#define MAX_BOOT_STATUS 512 - -/* Indicates how to encode SW components' measurements in the CBOR map */ -#define EAT_SW_COMPONENT_NESTED 1 /* Nested map */ -#define EAT_SW_COMPONENT_NOT_NESTED 0 /* Flat structure */ - -/* Indicates that the boot status does not contain any SW components' - * measurement - */ -#define NO_SW_COMPONENT_FIXED_VALUE 1 - -/*! - * \var boot_status - * - * \brief Array variable to store the boot status in service's memory. - * - * \details Boot status comes from the secure bootloader and primarily stored - * on a memory area which is shared between bootloader and SPM. - * SPM provides the \ref tfm_core_get_boot_data() API to retrieve - * the service related data from shared area. - */ - -/* Enforcement of 4 byte alignment, which is checked by TF-M SPM */ -__attribute__ ((aligned(4))) -static uint8_t boot_status[MAX_BOOT_STATUS]; - -enum psa_attest_err_t attest_init(void) -{ - enum psa_attest_err_t res; - - res = attest_get_boot_data(TLV_MAJOR_IAS, boot_status, MAX_BOOT_STATUS); - - return res; -} - -/*! - * \brief Static function to map return values between \ref attest_token_err_t - * and \ref psa_attest_err_t - * - * \param[in] token_err Token encoding return value - * - * \return Returns error code as specified in \ref psa_attest_err_t - */ -static inline enum psa_attest_err_t -error_mapping(enum attest_token_err_t token_err) -{ - switch (token_err) { - case ATTEST_TOKEN_ERR_SUCCESS: - return PSA_ATTEST_ERR_SUCCESS; - break; - case ATTEST_TOKEN_ERR_TOO_SMALL: - return PSA_ATTEST_ERR_TOKEN_BUFFER_OVERFLOW; - break; - default: - return PSA_ATTEST_ERR_GENERAL; - } -} - -/*! - * \brief Static function to convert a pointer and size info to unsigned - * integer number. Max 32bits unsigned integers are supported. - * - * This implementation assumes that the endianness of the sender and receiver - * of the data is the same because they are actually running on the same CPU - * instance. If this assumption is not true than this function must be - * refactored accordingly. - * - * \param[in] int_ptr Pointer to the unsigned integer - * \param[in] len Size of the unsigned integers in bytes - * \param[in] value Pointer where to store the converted value - * - * \return Returns 0 on success and -1 on error. - */ -static inline int32_t get_uint(const void *int_ptr, - size_t len, - uint32_t *value) -{ - uint16_t uint16; - - switch (len) { - case 1: - *value = (uint32_t)(*(uint8_t *)(int_ptr)); - break; - case 2: - /* Avoid unaligned access */ - tfm_memcpy(&uint16, int_ptr, sizeof(uint16)); - *value = (uint32_t)uint16; - break; - case 4: - /* Avoid unaligned access */ - tfm_memcpy(value, int_ptr, sizeof(uint32_t)); - break; - default: - return -1; - } - - return 0; -} -/*! - * \brief Static function to look up all entires in the shared data area - * (boot status) which belong to a specific module. - * - * \param[in] module The identifier of SW module to look up based on this - * \param[out] claim The type of SW module's attribute - * \param[out] tlv_len Length of the shared data entry - * \param[in/out] tlv_ptr Pointer to the shared data entry. If its value NULL as - * input then it will starts the look up from the - * beginning of the shared data section. If not NULL then - * it continue look up from the next entry. It returns - * the address of next found entry which belongs to - * module. - * - * \retval -1 Error, boot status is malformed - * \retval 0 Entry not found - * \retval 1 Entry found - */ -static int32_t attest_get_tlv_by_module(uint8_t module, - uint8_t *claim, - uint16_t *tlv_len, - uint8_t **tlv_ptr) -{ - struct shared_data_tlv_header *tlv_header; - struct shared_data_tlv_entry tlv_entry; - uint8_t *tlv_end; - uint8_t *tlv_curr; - - tlv_header = (struct shared_data_tlv_header *)boot_status; - if (tlv_header->tlv_magic != SHARED_DATA_TLV_INFO_MAGIC) { - return -1; - } - - /* Get the boundaries of TLV section where to lookup*/ - tlv_end = (uint8_t *)boot_status + tlv_header->tlv_tot_len; - if (*tlv_ptr == NULL) { - /* At first call set to the beginning of the TLV section */ - tlv_curr = (uint8_t *)boot_status + SHARED_DATA_HEADER_SIZE; - } else { - /* Any subsequent call set to the next TLV entry */ - tfm_memcpy(&tlv_entry, *tlv_ptr, SHARED_DATA_ENTRY_HEADER_SIZE); - tlv_curr = (*tlv_ptr) + tlv_entry.tlv_len; - } - - /* Iterates over the TLV section and returns the address and size of TLVs - * with requested module identifier - */ - for (; tlv_curr < tlv_end; tlv_curr += tlv_entry.tlv_len) { - /* Create local copy to avoid unaligned access */ - tfm_memcpy(&tlv_entry, tlv_curr, SHARED_DATA_ENTRY_HEADER_SIZE); - if (GET_IAS_MODULE(tlv_entry.tlv_type) == module) { - *claim = GET_IAS_CLAIM(tlv_entry.tlv_type); - *tlv_ptr = tlv_curr; - *tlv_len = tlv_entry.tlv_len; - return 1; - } - } - - return 0; -} - -/*! - * \brief Static function to look up specific claim belongs to SW_GENERAL module - * - * \param[in] claim The claim ID to look for - * \param[out] tlv_len Length of the shared data entry - * \param[out] tlv_ptr Pointer to a shared data entry which belongs to the - * SW_GENERAL module. - * - * \retval -1 Error, boot status is malformed - * \retval 0 Entry not found - * \retval 1 Entry found - */ -static int32_t attest_get_tlv_by_id(uint8_t claim, - uint16_t *tlv_len, - uint8_t **tlv_ptr) -{ - uint8_t tlv_id; - uint8_t module = SW_GENERAL; - int32_t found; - - /* Ensure that look up starting from the beginning of the boot status */ - *tlv_ptr = NULL; - - /* Look up specific TLV entry which belongs to SW_GENERAL module */ - do { - /* Look up next entry */ - found = attest_get_tlv_by_module(module, &tlv_id, - tlv_len, tlv_ptr); - if (found != 1) { - break; - } - /* At least one entry was found which belongs to SW_GENERAL, - * check whether this one is looked for - */ - if (claim == tlv_id) { - break; - } - } while (found == 1); - - return found; -} - -/*! - * \brief Static function to add SW component related claims to attestation - * token in CBOR format. - * - * This function translates between TLV and CBOR encoding. - * - * \param[in] token_ctx Attestation token encoding context - * \param[in] tlv_id The ID of claim - * \param[in] claim_value A structure which carries a pointer and size about - * the data item to be added to the token - * - * \return Returns error code as specified in \ref psa_attest_err_t - */ -static enum psa_attest_err_t -attest_add_sw_component_claim(struct attest_token_ctx *token_ctx, - uint8_t tlv_id, - const struct useful_buf_c *claim_value) -{ - int32_t res; - uint32_t value; - - switch (tlv_id) { - case SW_MEASURE_VALUE: - attest_token_add_bstr(token_ctx, - EAT_CBOR_SW_COMPONENT_MEASUREMENT_VALUE, - claim_value); - break; - case SW_MEASURE_TYPE: - attest_token_add_tstr(token_ctx, - EAT_CBOR_SW_COMPONENT_MEASUREMENT_DESC, - claim_value); - break; - case SW_VERSION: - attest_token_add_tstr(token_ctx, - EAT_CBOR_SW_COMPONENT_VERSION, - claim_value); - break; - case SW_SIGNER_ID: - attest_token_add_bstr(token_ctx, - EAT_CBOR_SW_COMPONENT_SIGNER_ID, - claim_value); - break; - case SW_EPOCH: - res = get_uint(claim_value->ptr, claim_value->len, &value); - if (res) { - return PSA_ATTEST_ERR_GENERAL; - } - attest_token_add_integer(token_ctx, - EAT_CBOR_SW_COMPONENT_SECURITY_EPOCH, - (int64_t)value); - break; - case SW_TYPE: - attest_token_add_tstr(token_ctx, - EAT_CBOR_SW_COMPONENT_MEASUREMENT_TYPE, - claim_value); - break; - default: - return PSA_ATTEST_ERR_GENERAL; - } - - return PSA_ATTEST_ERR_SUCCESS; -} - -/*! - * \brief Static function to add the measurement data of a single SW components - * to the attestation token. - * - * \param[in] token_ctx Token encoding context - * \param[in] module SW component identifier - * \param[in] tlv_address Address of the first TLV entry in the boot status, - * which belongs to this SW component. - * \param[in] nested_map Flag to indicate that how to encode the SW component - * measurement data: nested map or non-nested map. - * - * \return Returns error code as specified in \ref psa_attest_err_t - */ -static enum psa_attest_err_t -attest_add_single_sw_measurment(struct attest_token_ctx *token_ctx, - uint32_t module, - uint8_t *tlv_address, - uint32_t nested_map) -{ - struct shared_data_tlv_entry tlv_entry; - uint16_t tlv_len; - uint8_t tlv_id; - uint8_t *tlv_ptr = tlv_address; - int32_t found = 1; - struct useful_buf_c claim_value; - enum psa_attest_err_t res; - QCBOREncodeContext *cbor_encode_ctx; - - /* Create local copy to avoid unaligned access */ - tfm_memcpy(&tlv_entry, tlv_address, SHARED_DATA_ENTRY_HEADER_SIZE); - tlv_len = tlv_entry.tlv_len; - tlv_id = GET_IAS_CLAIM(tlv_entry.tlv_type); - - cbor_encode_ctx = attest_token_borrow_cbor_cntxt(token_ctx); - - /* Open nested map for SW component measurement claims */ - if (nested_map) { - QCBOREncode_OpenMapInMapN(cbor_encode_ctx, - EAT_CBOR_SW_COMPONENT_MEASUREMENT_VALUE); - } - - /* Look up all measurement TLV entry which belongs to the SW component */ - while (found) { - /* Here only measurement claims are added to the token */ - if (GET_IAS_MEASUREMENT_CLAIM(tlv_id)) { - claim_value.ptr = tlv_ptr + SHARED_DATA_ENTRY_HEADER_SIZE; - claim_value.len = tlv_len - SHARED_DATA_ENTRY_HEADER_SIZE; - res = attest_add_sw_component_claim(token_ctx, - tlv_id, - &claim_value); - if (res != PSA_ATTEST_ERR_SUCCESS) { - return res; - } - } - - /* Look up next entry it can be non-measurement claim*/ - found = attest_get_tlv_by_module(module, &tlv_id, - &tlv_len, &tlv_ptr); - if (found == -1) { - return PSA_ATTEST_ERR_CLAIM_UNAVAILABLE; - } - } - - if (nested_map) { - QCBOREncode_CloseMap(cbor_encode_ctx); - } - - return PSA_ATTEST_ERR_SUCCESS; -} - -/*! - * \brief Static function to add the claims of a single SW components to the - * attestation token. - * - * \param[in] token_ctx Token encoding context - * \param[in] module SW component identifier - * \param[in] tlv_address Address of the first TLV entry in the boot status, - * which belongs to this SW component. - * - * \return Returns error code as specified in \ref psa_attest_err_t - */ -static enum psa_attest_err_t -attest_add_single_sw_component(struct attest_token_ctx *token_ctx, - uint32_t module, - uint8_t *tlv_address) -{ - struct shared_data_tlv_entry tlv_entry; - uint16_t tlv_len; - uint8_t tlv_id; - uint8_t *tlv_ptr = tlv_address; - int32_t found = 1; - uint32_t measurement_claim_cnt = 0; - struct useful_buf_c claim_value; - QCBOREncodeContext *cbor_encode_ctx; - - /* Create local copy to avoid unaligned access */ - tfm_memcpy(&tlv_entry, tlv_address, SHARED_DATA_ENTRY_HEADER_SIZE); - tlv_len = tlv_entry.tlv_len; - tlv_id = GET_IAS_CLAIM(tlv_entry.tlv_type); - - /* Open map which stores claims belong to a SW component */ - cbor_encode_ctx = attest_token_borrow_cbor_cntxt(token_ctx); - QCBOREncode_OpenMap(cbor_encode_ctx); - - /*Look up all TLV entry which belongs to the same SW component */ - while (found) { - /* Check whether claim is measurement claim */ - if (GET_IAS_MEASUREMENT_CLAIM(tlv_id)) { - if (measurement_claim_cnt == 0) { - /* Call only once when first measurement claim found */ - measurement_claim_cnt++; - attest_add_single_sw_measurment(token_ctx, - module, - tlv_ptr, - EAT_SW_COMPONENT_NOT_NESTED); - } - } else { - /* Adding top level claims */ - claim_value.ptr = tlv_ptr + SHARED_DATA_ENTRY_HEADER_SIZE; - claim_value.len = tlv_len - SHARED_DATA_ENTRY_HEADER_SIZE; - attest_add_sw_component_claim(token_ctx, tlv_id, &claim_value); - } - - /* Look up next entry which belongs to SW component */ - found = attest_get_tlv_by_module(module, &tlv_id, - &tlv_len, &tlv_ptr); - if (found == -1) { - return PSA_ATTEST_ERR_CLAIM_UNAVAILABLE; - } - } - - /* Close map which stores claims belong to a SW component */ - QCBOREncode_CloseMap(cbor_encode_ctx); - - return PSA_ATTEST_ERR_SUCCESS; -} - -/*! - * \brief Static function to add the claims of all SW components to the - * attestation token. - * - * \param[in] token_ctx Token encoding context - * - * \return Returns error code as specified in \ref psa_attest_err_t - */ -static enum psa_attest_err_t -attest_add_all_sw_components(struct attest_token_ctx *token_ctx) -{ - uint16_t tlv_len; - uint8_t *tlv_ptr; - uint8_t tlv_id; - int32_t found; - uint32_t cnt = 0; - uint32_t module; - QCBOREncodeContext *cbor_encode_ctx; - - /* Starting from module 1, because module 0 contains general claims which - * are not related to SW module(i.e: boot_seed, etc.) - */ - for (module = 1; module < SW_MAX; ++module) { - /* Indicates to restart the look up from the beginning of the shared - * data section - */ - tlv_ptr = NULL; - - /* Look up the first TLV entry which belongs to the SW module */ - found = attest_get_tlv_by_module(module, &tlv_id, - &tlv_len, &tlv_ptr); - if (found == -1) { - return PSA_ATTEST_ERR_CLAIM_UNAVAILABLE; - } - - if (found == 1) { - cnt++; - if (cnt == 1) { - /* Open array which stores SW components claims */ - cbor_encode_ctx = attest_token_borrow_cbor_cntxt(token_ctx); - QCBOREncode_OpenArrayInMapN(cbor_encode_ctx, - EAT_CBOR_ARM_LABEL_SW_COMPONENTS); - } - attest_add_single_sw_component(token_ctx, module, tlv_ptr); - } - } - - if (cnt != 0) { - /* Close array which stores SW components claims*/ - QCBOREncode_CloseArray(cbor_encode_ctx); - } else { - /* If there is not any SW components' measurement in the boot status - * then include this claim to indicate that this state is intentional - */ - attest_token_add_integer(token_ctx, - EAT_CBOR_ARM_LABEL_NO_SW_COMPONENTS, - (int64_t)NO_SW_COMPONENT_FIXED_VALUE); - } - - return PSA_ATTEST_ERR_SUCCESS; -} - -/*! - * \brief Static function to add boot seed claim to attestation token. - * - * \param[in] token_ctx Token encoding context - * - * \return Returns error code as specified in \ref psa_attest_err_t - */ -static enum psa_attest_err_t -attest_add_boot_seed_claim(struct attest_token_ctx *token_ctx) -{ - /* FixMe: Enforcement of 4 byte alignment can be removed as soon as memory - * type is configured in the MPU to be normal, instead of device, - * which prohibits unaligned access. - */ - __attribute__ ((aligned(4))) - uint8_t boot_seed[BOOT_SEED_SIZE]; - enum tfm_plat_err_t res; - struct useful_buf_c claim_value = {0}; - uint16_t tlv_len; - uint8_t *tlv_ptr = NULL; - int32_t found = 0; - - /* First look up BOOT_SEED in boot status, it might comes from bootloader */ - found = attest_get_tlv_by_id(BOOT_SEED, &tlv_len, &tlv_ptr); - if (found == 1) { - claim_value.ptr = tlv_ptr + SHARED_DATA_ENTRY_HEADER_SIZE; - claim_value.len = tlv_len - SHARED_DATA_ENTRY_HEADER_SIZE; - } else { - /* If not found in boot status then use callback function to get it - * from runtime SW - */ - res = tfm_plat_get_boot_seed(sizeof(boot_seed), boot_seed); - if (res != TFM_PLAT_ERR_SUCCESS) { - return PSA_ATTEST_ERR_CLAIM_UNAVAILABLE; - } - claim_value.ptr = boot_seed; - claim_value.len = BOOT_SEED_SIZE; - } - - attest_token_add_bstr(token_ctx, - EAT_CBOR_ARM_LABEL_BOOT_SEED, - &claim_value); - - return PSA_ATTEST_ERR_SUCCESS; -} - -/* FixMe: Remove this #if when MPU will be configured properly. Currently - * in case of TFM_LVL == 3 unaligned access triggers a usage fault - * exception. - */ -#if !defined(TFM_LVL) || (TFM_LVL == 1) -/*! - * \brief Static function to add instance id claim to attestation token. - * - * \param[in] token_ctx Token encoding context - * - * \return Returns error code as specified in \ref psa_attest_err_t - */ -static enum psa_attest_err_t -attest_add_instance_id_claim(struct attest_token_ctx *token_ctx) -{ - /* FixMe: Enforcement of 4 byte alignment can be removed as soon as memory - * type is configured in the MPU to be normal, instead of device, - * which prohibits unaligned access. - */ - __attribute__ ((aligned(4))) - uint8_t instance_id[INSTANCE_ID_MAX_SIZE]; - enum tfm_plat_err_t res_plat; - uint32_t size = sizeof(instance_id); - struct useful_buf_c claim_value; - - res_plat = tfm_plat_get_instance_id(&size, instance_id); - if (res_plat != TFM_PLAT_ERR_SUCCESS) { - return PSA_ATTEST_ERR_CLAIM_UNAVAILABLE; - } - - claim_value.ptr = instance_id; - claim_value.len = size; - attest_token_add_bstr(token_ctx, - EAT_CBOR_ARM_LABEL_UEID, - &claim_value); - - return PSA_ATTEST_ERR_SUCCESS; -} - -/*! - * \brief Static function to add implementation id claim to attestation token. - * - * \param[in] token_ctx Token encoding context - * - * \return Returns error code as specified in \ref psa_attest_err_t - */ -static enum psa_attest_err_t -attest_add_implementation_id_claim(struct attest_token_ctx *token_ctx) -{ - /* FixMe: Enforcement of 4 byte alignment can be removed as soon as memory - * type is configured in the MPU to be normal, instead of device, - * which prohibits unaligned access. - */ - __attribute__ ((aligned(4))) - uint8_t implementation_id[IMPLEMENTATION_ID_MAX_SIZE]; - enum tfm_plat_err_t res_plat; - uint32_t size = sizeof(implementation_id); - struct useful_buf_c claim_value; - - res_plat = tfm_plat_get_implementation_id(&size, implementation_id); - if (res_plat != TFM_PLAT_ERR_SUCCESS) { - return PSA_ATTEST_ERR_CLAIM_UNAVAILABLE; - } - - claim_value.ptr = implementation_id; - claim_value.len = size; - attest_token_add_bstr(token_ctx, - EAT_CBOR_ARM_LABEL_IMPLEMENTATION_ID, - &claim_value); - - return PSA_ATTEST_ERR_SUCCESS; -} - -/*! - * \brief Static function to add hardware version claim to attestation token. - * - * \param[in] token_ctx Token encoding context - * - * \return Returns error code as specified in \ref psa_attest_err_t - */ -static enum psa_attest_err_t -attest_add_hw_version_claim(struct attest_token_ctx *token_ctx) -{ - /* FixMe: Enforcement of 4 byte alignment can be removed as soon as memory - * type is configured in the MPU to be normal, instead of device, - * which prohibits unaligned access. - */ - __attribute__ ((aligned(4))) - uint8_t hw_version[HW_VERSION_MAX_SIZE]; - enum tfm_plat_err_t res_plat; - uint32_t size = sizeof(hw_version); - struct useful_buf_c claim_value = {0}; - uint16_t tlv_len; - uint8_t *tlv_ptr = NULL; - int32_t found = 0; - - /* First look up HW version in boot status, it might comes - * from bootloader - */ - found = attest_get_tlv_by_id(HW_VERSION, &tlv_len, &tlv_ptr); - if (found == 1) { - claim_value.ptr = tlv_ptr + SHARED_DATA_ENTRY_HEADER_SIZE; - claim_value.len = tlv_len - SHARED_DATA_ENTRY_HEADER_SIZE; - } else { - /* If not found in boot status then use callback function to get it - * from runtime SW - */ - res_plat = tfm_plat_get_hw_version(&size, hw_version); - if (res_plat != TFM_PLAT_ERR_SUCCESS) { - return PSA_ATTEST_ERR_CLAIM_UNAVAILABLE; - } - claim_value.ptr = hw_version; - claim_value.len = size; - } - - attest_token_add_tstr(token_ctx, - EAT_CBOR_ARM_LABEL_HW_VERSION, - &claim_value); - - return PSA_ATTEST_ERR_SUCCESS; -} -#endif - -/*! - * \brief Static function to add caller id claim to attestation token. - * - * \param[in] token_ctx Token encoding context - * - * \return Returns error code as specified in \ref psa_attest_err_t - */ -static enum psa_attest_err_t -attest_add_caller_id_claim(struct attest_token_ctx *token_ctx) -{ - enum psa_attest_err_t res; - int32_t caller_id; - - res = attest_get_caller_client_id(&caller_id); - if (res != PSA_ATTEST_ERR_SUCCESS) { - return res; - } - - attest_token_add_integer(token_ctx, - EAT_CBOR_ARM_LABEL_CLIENT_ID, - (int64_t)caller_id); - - return PSA_ATTEST_ERR_SUCCESS; -} - -/*! - * \brief Static function to add security lifecycle claim to attestation token. - * - * \param[in] token_ctx Token encoding context - * - * \return Returns error code as specified in \ref psa_attest_err_t - */ - -static enum psa_attest_err_t -attest_add_security_lifecycle_claim(struct attest_token_ctx *token_ctx) -{ - enum tfm_security_lifecycle_t security_lifecycle; - uint32_t slc_value; - int32_t res; - struct useful_buf_c claim_value = {0}; - uint16_t tlv_len; - uint8_t *tlv_ptr = NULL; - int32_t found = 0; - - /* First look up lifecycle state in boot status, it might comes - * from bootloader - */ - found = attest_get_tlv_by_id(SECURITY_LIFECYCLE, &tlv_len, &tlv_ptr); - if (found == 1) { - claim_value.ptr = tlv_ptr + SHARED_DATA_ENTRY_HEADER_SIZE; - claim_value.len = tlv_len - SHARED_DATA_ENTRY_HEADER_SIZE; - res = get_uint(claim_value.ptr, claim_value.len, &slc_value); - if (res) { - return PSA_ATTEST_ERR_GENERAL; - } - security_lifecycle = (enum tfm_security_lifecycle_t)slc_value; - } else { - /* If not found in boot status then use callback function to get it - * from runtime SW - */ - security_lifecycle = tfm_attest_hal_get_security_lifecycle(); - } - - /* Sanity check */ - if (security_lifecycle < TFM_SLC_UNKNOWN || - security_lifecycle > TFM_SLC_DECOMMISSIONED) { - return PSA_ATTEST_ERR_GENERAL; - } - - attest_token_add_integer(token_ctx, - EAT_CBOR_ARM_LABEL_SECURITY_LIFECYCLE, - (int64_t)security_lifecycle); - - return PSA_ATTEST_ERR_SUCCESS; -} - -/*! - * \brief Static function to add challenge claim to attestation token. - * - * \param[in] token_ctx Token encoding context - * \param[in] challenge Pointer to buffer which stores the challenge - * - * \return Returns error code as specified in \ref psa_attest_err_t - */ -static enum psa_attest_err_t -attest_add_challenge_claim(struct attest_token_ctx *token_ctx, - const struct useful_buf_c *challenge) -{ - attest_token_add_bstr(token_ctx, EAT_CBOR_ARM_LABEL_CHALLENGE, challenge); - - return PSA_ATTEST_ERR_SUCCESS; -} - -/*! - * \brief Static function to add the verification service indicator claim - * to the attestation token. - * - * \param[in] token_ctx Token encoding context - * - * \return Returns error code as specified in \ref psa_attest_err_t - */ -static enum psa_attest_err_t -attest_add_verification_service(struct attest_token_ctx *token_ctx) -{ - struct useful_buf_c service; - uint32_t size; - - service.ptr = tfm_attest_hal_get_verification_service(&size); - - if (service.ptr) { - service.len = size; - attest_token_add_tstr(token_ctx, - EAT_CBOR_ARM_LABEL_ORIGINATION, - &service); - } - - return PSA_ATTEST_ERR_SUCCESS; -} - -/*! - * \brief Static function to add the name of the profile definition document - * - * \param[in] token_ctx Token encoding context - * - * \return Returns error code as specified in \ref psa_attest_err_t - */ -static enum psa_attest_err_t -attest_add_profile_definition(struct attest_token_ctx *token_ctx) -{ - struct useful_buf_c profile; - uint32_t size; - - profile.ptr = tfm_attest_hal_get_profile_definition(&size); - - if (profile.ptr) { - profile.len = size; - attest_token_add_tstr(token_ctx, - EAT_CBOR_ARM_LABEL_PROFILE_DEFINITION, - &profile); - } - - return PSA_ATTEST_ERR_SUCCESS; -} - -/*! - * \brief Static function to verify the input challenge size - * - * Only discrete sizes are accepted. - * - * \param[in] challenge_size Size of challenge object in bytes. - * - * \retval PSA_ATTEST_ERR_SUCCESS - * \retval PSA_ATTEST_ERR_INVALID_INPUT - */ -static enum psa_attest_err_t attest_verify_challenge_size(size_t challenge_size) -{ - switch (challenge_size) { - /* Intentional fall through */ - case PSA_INITIAL_ATTEST_CHALLENGE_SIZE_32: - case PSA_INITIAL_ATTEST_CHALLENGE_SIZE_48: - case PSA_INITIAL_ATTEST_CHALLENGE_SIZE_64: - case (PSA_INITIAL_ATTEST_CHALLENGE_SIZE_32 + 4): /* Test purpose */ - return PSA_ATTEST_ERR_SUCCESS; - } - - return PSA_ATTEST_ERR_INVALID_INPUT; -} - -/*! - * \brief Static function to create the initial attestation token - * - * \param[in] challenge Structure to carry the challenge value: - * pointer + challeng's length - * \param[in] token Structure to carry the token info, where to - * create it: pointer + buffer's length - * \param[out] completed_token Structure to carry the info about the created - * token: pointer + final token's length - * - * \return Returns error code as specified in \ref psa_attest_err_t - */ -static enum psa_attest_err_t -attest_create_token(struct useful_buf_c *challenge, - struct useful_buf *token, - struct useful_buf_c *completed_token) -{ - enum psa_attest_err_t attest_err = PSA_ATTEST_ERR_SUCCESS; - enum attest_token_err_t token_err; - struct attest_token_ctx attest_token_ctx; - int32_t key_select; - uint32_t option_flags = 0; - - if (challenge->len == 36) { - /* FixMe: Special challenge with option flags appended. This might can - * be removed when the public API can take option_flags. - */ - option_flags = *(uint32_t *)((uint8_t*)challenge->ptr + 32); - challenge->len = 32; - } - - /* Lower three bits are the key select */ - key_select = option_flags & 0x7; - - /* Get started creating the token. This sets up the CBOR and COSE contexts - * which causes the COSE headers to be constructed. - */ - token_err = attest_token_start(&attest_token_ctx, - option_flags, /* option_flags */ - key_select, /* key_select */ - COSE_ALGORITHM_ES256, /* alg_select */ - token); - - if (token_err != ATTEST_TOKEN_ERR_SUCCESS) { - attest_err = error_mapping(token_err); - goto error; - } - - attest_err = attest_add_challenge_claim(&attest_token_ctx, - challenge); - if (attest_err != PSA_ATTEST_ERR_SUCCESS) { - goto error; - } - - if (!(option_flags & TOKEN_OPT_OMIT_CLAIMS)) { - attest_err = attest_add_boot_seed_claim(&attest_token_ctx); - if (attest_err != PSA_ATTEST_ERR_SUCCESS) { - goto error; - } - - attest_err = attest_add_verification_service(&attest_token_ctx); - if (attest_err != PSA_ATTEST_ERR_SUCCESS) { - goto error; - } - - attest_err = attest_add_profile_definition(&attest_token_ctx); - if (attest_err != PSA_ATTEST_ERR_SUCCESS) { - goto error; - } - - /* FixMe: Remove this #if when MPU will be configured properly. - * Currently in case of TFM_LVL == 3 unaligned access triggers - * a usage fault exception. - */ -#if !defined(TFM_LVL) || (TFM_LVL == 1) - attest_err = attest_add_instance_id_claim(&attest_token_ctx); - if (attest_err != PSA_ATTEST_ERR_SUCCESS) { - goto error; - } - - attest_err = attest_add_hw_version_claim(&attest_token_ctx); - if (attest_err != PSA_ATTEST_ERR_SUCCESS) { - goto error; - } - - attest_err = attest_add_implementation_id_claim(&attest_token_ctx); - if (attest_err != PSA_ATTEST_ERR_SUCCESS) { - goto error; - } -#endif - - attest_err = attest_add_caller_id_claim(&attest_token_ctx); - if (attest_err != PSA_ATTEST_ERR_SUCCESS) { - goto error; - } - - attest_err = attest_add_security_lifecycle_claim(&attest_token_ctx); - if (attest_err != PSA_ATTEST_ERR_SUCCESS) { - goto error; - } - - attest_err = attest_add_all_sw_components(&attest_token_ctx); - if (attest_err != PSA_ATTEST_ERR_SUCCESS) { - goto error; - } - } - - /* Finish up creating the token. This is where the actual signature - * is generated. This finishes up the CBOR encoding too. - */ - token_err = attest_token_finish(&attest_token_ctx, completed_token); - if (token_err) { - attest_err = error_mapping(token_err); - goto error; - } - -error: - return attest_err; -} - -/* Limitations of the current implementation: - * - Token is not signed yet properly, just a fake signature is added to the - * token due to lack of psa_sign_hash() implementation in crypto - * service. - */ -enum psa_attest_err_t -initial_attest_get_token(const psa_invec *in_vec, uint32_t num_invec, - psa_outvec *out_vec, uint32_t num_outvec) -{ - enum psa_attest_err_t attest_err = PSA_ATTEST_ERR_SUCCESS; - struct useful_buf_c challenge; - struct useful_buf token; - struct useful_buf_c completed_token; - - challenge.ptr = in_vec[0].base; - challenge.len = in_vec[0].len; - token.ptr = out_vec[0].base; - token.len = out_vec[0].len; - - attest_err = attest_verify_challenge_size(challenge.len); - if (attest_err != PSA_ATTEST_ERR_SUCCESS) { - goto error; - } - - attest_err = attest_check_memory_access((void *)challenge.ptr, - challenge.len, - TFM_ATTEST_ACCESS_RO); - if (attest_err != PSA_ATTEST_ERR_SUCCESS) { - goto error; - } - - attest_err = attest_check_memory_access(token.ptr, - token.len, - TFM_ATTEST_ACCESS_RW); - if (attest_err != PSA_ATTEST_ERR_SUCCESS) { - goto error; - } - - attest_err = attest_create_token(&challenge, &token, &completed_token); - if (attest_err != PSA_ATTEST_ERR_SUCCESS) { - goto error; - } - - out_vec[0].base = (void *)completed_token.ptr; - out_vec[0].len = completed_token.len; - -error: - return attest_err; -} - -/* Initial implementation, just returns with hard coded value */ -enum psa_attest_err_t -initial_attest_get_token_size(const psa_invec *in_vec, uint32_t num_invec, - psa_outvec *out_vec, uint32_t num_outvec) -{ - enum psa_attest_err_t attest_err = PSA_ATTEST_ERR_SUCCESS; - uint32_t challenge_size = *(uint32_t *)in_vec[0].base; - uint32_t *token_buf_size = (uint32_t *)out_vec[0].base; - struct useful_buf_c challenge; - struct useful_buf token; - struct useful_buf_c completed_token; - - /* Only the size of the challenge is needed */ - challenge.ptr = NULL; - challenge.len = challenge_size; - - /* Special value to get the size of the token, but token is not created */ - token.ptr = NULL; - token.len = INT32_MAX; - - if (out_vec[0].len < sizeof(uint32_t)) { - attest_err = PSA_ATTEST_ERR_INVALID_INPUT; - goto error; - } - - attest_err = attest_verify_challenge_size(challenge_size); - if (attest_err != PSA_ATTEST_ERR_SUCCESS) { - goto error; - } - - attest_err = attest_create_token(&challenge, &token, &completed_token); - if (attest_err != PSA_ATTEST_ERR_SUCCESS) { - goto error; - } - - *token_buf_size = completed_token.len; - -error: - return attest_err; -} diff --git a/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/t_cose/CMakeLists.txt b/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/t_cose/CMakeLists.txt deleted file mode 100644 index e1f1985..0000000 --- a/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/t_cose/CMakeLists.txt +++ /dev/null @@ -1,40 +0,0 @@ -#------------------------------------------------------------------------------- -# Copyright (c) 2019, Arm Limited. All rights reserved. -# -# SPDX-License-Identifier: BSD-3-Clause -# -#------------------------------------------------------------------------------- - -cmake_minimum_required(VERSION 3.7) - -#Tell cmake where our modules can be found -list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/../../../cmake) - -#Include common stuff to control cmake. -include("Common/BuildSys") - -#Start an embedded project. -embedded_project_start(CONFIG "${CMAKE_CURRENT_LIST_DIR}/../../ConfigDefault.cmake") -project(tfm_t_cose LANGUAGES C) -embedded_project_fixup() - -#Some project global settings -set(T_COSE_DIR "${CMAKE_CURRENT_LIST_DIR}") - -#Append all our source files to global lists. -list(APPEND ALL_SRC_C - "${T_COSE_DIR}/src/t_cose_sign1_sign.c" - "${T_COSE_DIR}/src/t_cose_util.c" - "${T_COSE_DIR}/src/t_cose_psa_crypto.c" - ) - -#Setting include directories -embedded_include_directories(PATH ${T_COSE_DIR}/inc ABSOLUTE) - -#Specify what we build (for the t_cose, build as an object library) -add_library(${PROJECT_NAME} OBJECT ${ALL_SRC_C}) - -#Set common compiler flags -config_setting_shared_compiler_flags(${PROJECT_NAME}) - -embedded_project_end(${PROJECT_NAME}) diff --git a/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/t_cose/README.md b/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/t_cose/README.md deleted file mode 100644 index 9501806..0000000 --- a/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/t_cose/README.md +++ /dev/null @@ -1,95 +0,0 @@ -# t_cose - -## Introduction - -t_cose is a partial implementation of the COSE standard (RFC 8152). -COSE is quite a large standard so a full implementation of all of it -is a large undertaking. This implementation is starting out as just -enough for attestation and maybe CWT (Cbor Web Token) which is very -similar. - -As it may grow to support more of COSE over time, it is structured -with that in mind. - -It is also trying to be portable, the most interesting part of which -is interfacing with the libraries for performing cryptography and -access cryptographic keys. - -## Source files -The following files are more or less the public interface. -* t_cose_common.h -* t_cose_sign1.h -* t_cose_sign1_verify.h - -The rest of the files are internal source files that callers should -not depend on. - -t_cose_defines.h contains contants from RFC 8152 that are -part of the COSE standard. It should never have anything else -in it. - -t_cose_util is some utilities and code common to -signing and verification. Both signing and verifcation -depend on it. - -t_cose_crypto is the crypto porting layer. Generally -the .h file should not need to change for a new -platform. The .c file will be changed lots for -each new platform. - -## Dependency and Portability -t_cose is attempting to be very portable and -have a minmum number of #ifdefs. It is -designed to run 64-bit and 32-bit machines. - -It uses a minimum number of standard C -libraries, mostly just , and . - -It uses QCBOR for CBOR encoding and decoding. -QCBOR is very portable. - -### Cryptography and Keys -There is a cryptographic adaption layer that -provides the following: -* Impedence match of parameters passed to/from the crypto -* Management of algorithm identifiers -* Management of error codes -* Management of key identifiers - -It is framed for the needs of t_cose, and is -not trying to be any kind of general crypto API. - -#### Question -Q: How many crypto APIs does it take to screw in a light bulb? -A: One more than it takes to screw in a light bulb. - -## Copyright and License - -### BSD-3-Clause license - -* Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright -notice, this list of conditions and the following disclaimer in the -documentation and/or other materials provided with the distribution. - -* Neither the name of the copyright holder nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -### Copyright for this README - -Copyright (c) 2018-2019, Laurence Lundblade. All rights reserved. diff --git a/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/t_cose/inc/t_cose_common.h b/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/t_cose/inc/t_cose_common.h deleted file mode 100644 index d509a4b..0000000 --- a/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/t_cose/inc/t_cose_common.h +++ /dev/null @@ -1,148 +0,0 @@ -/* - * t_cose_common.h - * - * Copyright 2019, Laurence Lundblade - * - * SPDX-License-Identifier: BSD-3-Clause - * - * See BSD-3-Clause license in README.mdE. - */ - - -#ifndef __T_COSE_COMMON_H__ -#define __T_COSE_COMMON_H__ - - -/** - * \file t_cose_common.h - * - * \brief Defines common to all public t_cose interfaces. - * - */ - - -/* Private value. Intentionally not documented for Doxygen. - * This is the size allocated for the encoded protected headers. It - * needs to be big enough for make_protected_header() to succeed. It - * currently sized for one header with an algorithm ID up to 32 bits - * long -- one byte for the wrapping map, one byte for the label, 5 - * bytes for the ID. If this is made accidentially too small, QCBOR will - * only return an error, and not overrun any buffers. - * - * 9 extra bytes are added, rounding it up to 16 total, in case some - * other protected header is to be added. - */ -#define T_COSE_SIGN1_MAX_PROT_HEADER (1+1+5+9) - - -/** - * Error codes return by t_cose. - * - * Do not reorder these. It is OK to add - * new ones at the end. - */ -enum t_cose_err_t { - /** - * Operation completed successfully - */ - T_COSE_SUCCESS = 0, - /** - * The requested signing algorithm is not supported. - */ - T_COSE_ERR_UNSUPPORTED_SIGNING_ALG, - /** - * Error constructing the protected headers. - */ - T_COSE_ERR_PROTECTED_HEADERS, - /** - * The hash algorithm needed is not supported. Note that the - * signing algorithm identifier usually identifies the hash - * algorithm. - */ - T_COSE_ERR_UNSUPPORTED_HASH, - /** - * Some system failure when running the hash algorithm. - */ - T_COSE_ERR_HASH_GENERAL_FAIL, - /** - * The buffer to receive a hash result is too small. - */ - T_COSE_ERR_HASH_BUFFER_SIZE, - /** - * The buffer to receive result of a signing operation is too - * small. - */ - T_COSE_ERR_SIG_BUFFER_SIZE, - /** - * The buffer to receive to receive a key is too small. - */ - T_COSE_ERR_KEY_BUFFER_SIZE, - /** - * When verifying a \c COSE_Sign1, something is wrong with the - * format of the CBOR. For example, it is missing something like - * the payload. - */ - T_COSE_ERR_SIGN1_FORMAT, - /** - * When decoding some CBOR like a \c COSE_Sign1, the CBOR was not - * well-formed. Most likely what was supposed to be CBOR was is - * either not or it has been corrupted. - */ - T_COSE_ERR_CBOR_NOT_WELL_FORMED, - /** - * No algorithm ID was found when one is needed. For example, when - * verifying a \c COSE_Sign1. - */ - T_COSE_ERR_NO_ALG_ID, - /** - * No key ID was found when one is needed. For example, when - * verifying a \c COSE_Sign1. - */ - T_COSE_ERR_NO_KID, - /** - * Signature verification failed. For example, the cryptographic - * operations completed successfully but hash wasn't as expected. - */ - T_COSE_ERR_SIG_VERIFY, - /** - * Verification of a short-circuit signature failed. - */ - T_COSE_ERR_BAD_SHORT_CIRCUIT_KID, - /** - * Some (unspecified) argument was not valid. - */ - T_COSE_ERR_INVALID_ARGUMENT, - /** - * Out of heap memory. - */ - T_COSE_ERR_INSUFFICIENT_MEMORY, - /** - * General unspecific failure. - */ - T_COSE_ERR_FAIL, - /** - * Equivalent to \c PSA_ERROR_TAMPERING_DETECTED. - */ - T_COSE_ERR_TAMPERING_DETECTED, - /** - * The key identified by a key slot of a key ID was not found. - */ - T_COSE_ERR_UNKNOWN_KEY, - /** - * The key was found, but it was the wrong type for the operation. - */ - T_COSE_ERR_WRONG_TYPE_OF_KEY, - /** - * Error constructing the \c Sig_structure when signing or verify. - */ - T_COSE_ERR_SIG_STRUCT, - /** - * Signature was short-circuit. THe option to allow verification - * of short-circuit signatures was not set - */ - T_COSE_ERR_SHORT_CIRCUIT_SIG -}; - - - -#endif /* __T_COSE_COMMON_H__ */ diff --git a/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/t_cose/inc/t_cose_sign1_sign.h b/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/t_cose/inc/t_cose_sign1_sign.h deleted file mode 100644 index 35b26e5..0000000 --- a/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/t_cose/inc/t_cose_sign1_sign.h +++ /dev/null @@ -1,181 +0,0 @@ -/* - * t_cose_sign1_sign.h - * - * Copyright (c) 2018-2019, Laurence Lundblade. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - * - * See BSD-3-Clause license in README.md - */ - -#ifndef __T_COSE_SIGN1_H__ -#define __T_COSE_SIGN1_H__ - -#include -#include -#include "qcbor.h" -#include "t_cose_common.h" - - -/** - * \file t_cose_sign1_sign.h - * - * \brief Create a \c COSE_Sign1, usually for EAT or CWT Token. - * - * This creates a \c COSE_Sign1 in compliance with [COSE (RFC 8152)] - * (https://tools.ietf.org/html/rfc8152). A \c COSE_Sign1 is a CBOR - * encoded binary blob that contains headers, a payload and a - * signature. Usually the signature is made with an EC signing - * algorithm like ECDSA. - * - * This implementation is intended to be small and portable to - * different OS's and platforms. Its dependencies are: - * - QCBOR - * - , , - * - Hash functions like SHA-256 - * - Signing functions like ECDSA - * - * There is a cryptographic adaptation layer defined in - * t_cose_crypto.h. An implementation can be made of the functions in - * it for different platforms or OS's. This means that different - * platforms and OS's may support only signing with a particular set - * of algorithms. - * - * This \c COSE_Sign1 implementations is optimized for creating EAT - * tokens. - * - * It should work for CWT and others use cases too. The main point of - * the optimization is that only one output buffer is needed. There is - * no need for one buffer to hold the payload and another to hold the - * end result \c COSE_Sign1. The payload is encoded right into its final - * place in the end result \c COSE_Sign1. - */ - - -/** - * This is the context for creating a \c COSE_Sign1 structure. The caller - * should allocate it and pass it to the functions here. This is - * about 32 bytes so it fits easily on the stack. - */ -struct t_cose_sign1_ctx { - /* Private data structure */ - uint8_t buffer_for_protected_headers[ - T_COSE_SIGN1_MAX_PROT_HEADER]; - struct useful_buf_c protected_headers; - int32_t cose_algorithm_id; - int32_t key_select; - bool short_circuit_sign; - QCBOREncodeContext *cbor_encode_ctx; -}; - - -/** - * \brief Initialize to start creating a \c COSE_Sign1. - * - * \param[in] me The t_cose signing context. - * \param[in] short_circuit_sign \c true to select special test mode. - * \param[in] cose_algorithm_id The algorithm to sign with. The IDs are - * defined in [COSE (RFC 8152)] - * (https://tools.ietf.org/html/rfc8152) or - * in the [IANA COSE Registry] - * (https://www.iana.org/assignments/cose/cose.xhtml). - * \param[in] key_select Which signing key to use. - * \param[in] cbor_encode_ctx The CBOR encoder context to output to. - * - * \return This returns one of the error codes defined by \ref t_cose_err_t. - * - * It is possible to use this to compute the exact size of the - * resulting token so the exact sized buffer can be allocated. To do - * this initialize the \c cbor_encode_ctx with \c UsefulBufC that has - * a \c NULL pointer and large length like \c UINT32_MAX. Then run the - * normal token creation. The result will have a NULL pointer and the - * length of the token that would have been created. When this is run - * like this, the cryptographic functions will not actually run, but - * the size of their output will be taken into account. - * - * The key selection depends on the platform / OS. - * - * Which signing algorithms are supported depends on the platform/OS. - * The header file t_cose_defines.h contains defined constants for - * some of them. A typical example is \ref COSE_ALGORITHM_ES256 which - * indicates ECDSA with the NIST P-256 curve and SHA-256. - * - * To use this, create a \c QCBOREncodeContext and initialize it with - * an output buffer big enough to hold the payload and the COSE Sign 1 - * overhead. This overhead is about 30 bytes plus the size of the - * signature and the size of the key ID. - * - * After the \c QCBOREncodeContext is initialized, call - * t_cose_sign1_init() on it. - * - * Next call \c QCBOREncode_BstrWrap() to indicate the start of the - * payload. - * - * Next call various \c QCBOREncode_Addxxxx() methods to create the - * payload. - * - * Next call \c QCBOREncode_CloseBstrWrap() to indicate the end of the - * payload. This will also return a pointer and length of the payload - * that gets hashed. - * - * Next call t_cose_sign1_finish() with the pointer and length of the - * payload. This will do all the cryptography and complete the COSE - * Sign1. - * - * Finally, call \c QCBOREncode_Finish() to get the pointer and length - * of the complete token. - * - * This implements a special signing test mode called _short_ - * _circuit_ _signing_. This mode is useful when there is no signing - * key available, perhaps because it has not been provisioned or - * configured for the particular device. It may also be because the - * public key cryptographic functions have not been connected up in - * the cryptographic adaptation layer. - * - * It has no value for security at all. Data signed this way should - * not be trusted as anyone can sign like this. - * - * In this mode the signature is the hash of that would normally be - * signed by the public key algorithm. To make the signature the - * correct size for the particular algorithm instances of the hash are - * concatenated to pad it out. - * - * This mode is very useful for testing because all the code except - * the actual signing algorithm is run exactly as it would if a proper - * signing algorithm was run. - * - * The kid (Key ID) put in the unprotected headers is created as - * follows. The EC public key is CBOR encoded as a \c COSE_Key as - * defined in the COSE standard. That encoded CBOR is then - * hashed with SHA-256. This is similar to key IDs defined in IETF - * PKIX, but is based on COSE and CBOR rather than ASN.1. - */ -enum t_cose_err_t t_cose_sign1_init(struct t_cose_sign1_ctx *me, - bool short_circuit_sign, - int32_t cose_algorithm_id, - int32_t key_select, - QCBOREncodeContext *cbor_encode_ctx); - - -/** - * \brief Finish creation of the \c COSE_Sign1. - * - * \param[in] me The t_cose signing context. - * \param[in] payload The pointer and length of the payload. - * - * \return This returns one of the error codes defined by \ref t_cose_err_t. - * - * Call this to complete creation of a signed token started with - * t_cose_sign1_init(). - * - * This is when the signature algorithm is run. - * - * The payload parameter is used only to compute the hash for - * signing. The completed \c COSE_Sign1 is retrieved from the \c - * cbor_encode_ctx by calling \c QCBOREncode_Finish() - */ -enum t_cose_err_t t_cose_sign1_finish(struct t_cose_sign1_ctx *me, - struct useful_buf_c payload); - - -#endif /* __T_COSE_SIGN1_H__ */ diff --git a/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/t_cose/src/t_cose_crypto.h b/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/t_cose/src/t_cose_crypto.h deleted file mode 100644 index ab4faac..0000000 --- a/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/t_cose/src/t_cose_crypto.h +++ /dev/null @@ -1,413 +0,0 @@ -/* - * t_cose_crypto.h - * - * Copyright 2019, Laurence Lundblade - * - * SPDX-License-Identifier: BSD-3-Clause - * - * See BSD-3-Clause license in README.mdE. - */ - - -#ifndef __T_COSE_CRYPTO_H__ -#define __T_COSE_CRYPTO_H__ - -#include "t_cose_common.h" -#include "useful_buf.h" -#include -#include "t_cose_defines.h" - - -/** - * \file t_cose_crypto.h - * - * \brief This is the adaptation layer for cryptographic functions used by - * t_cose. - * - * This is small wrapper around the cryptographic functions to: - * - Map COSE algorithm IDs to TF-M algorithm IDs - * - Map crypto errors to \ref t_cose_err_t errors - * - Have inputs and outputs be \c struct \c useful_buf_c and - * \c struct \c useful_buf - * - Handle key selection - * - * The idea is that implementations can be made of these functions - * that adapt to various cryptographic libraries that are used on - * various platforms and OSs. - * - * This runs entirely off of COSE-style algorithm identifiers. They - * are simple integers and thus work nice as function parameters. An - * initial set is defined by [COSE (RFC 8152)] - * (https://tools.ietf.org/html/rfc8152). New ones can be registered - * in the [IANA COSE Registry] - * (https://www.iana.org/assignments/cose/cose.xhtml). Local use new - * ones can also be defined (\c \#define) if what is needed is not in - * the IANA registry. - * - * Binary data is returned to the caller using a \c struct \c - * useful_buf to pass the buffer to receive the data and its length in - * and a \c useful_buf_c to return the pointer and length of the - * returned data. The point of this is coding hygiene. The buffer - * passed in is not const as it is to be modified. The \c - * useful_buf_c returned is const. - * - * The pointer in the \c useful_buf_c will always point to the buffer - * passed in via the \c useful_buf so the lifetime of the data is - * under control of the caller. - * - * This is not intended as any sort of general cryptographic API. It - * is just the functions needed by t_cose in the form that is most - * useful for t_cose. - */ - - -/** - * Size of the signature output for the NIST P-256 Curve. - */ -#define T_COSE_EC_P256_SIG_SIZE 64 - -/** - * Size of the largest signature of any of the algorithm types - * supported. - * - * This will have to be adjusted if support for other algorithms - * larger is added. - * - * This is a compile time constant so it can be used to define stack - * variable sizes. - */ -#define T_COSE_MAX_EC_SIG_SIZE T_COSE_EC_P256_SIG_SIZE - - -/** - * \brief Get the size in bytes of a particular signature type. - * - * \param[in] cose_sig_alg_id The COSE algorithm ID. - * - * \return The size in bytes of the signature for a public-key signing - * algorithm. - */ -static inline size_t t_cose_signature_size(int32_t cose_sig_alg_id); - - -/** - * \brief Perform public key signing. Part of the t_cose crypto - * adaptation layer. - * - * \param[in] cose_alg_id The algorithm to sign with. The IDs are - * defined in [COSE (RFC 8152)] - * (https://tools.ietf.org/html/rfc8152) or - * in the [IANA COSE Registry] - * (https://www.iana.org/assignments/cose/cose.xhtml). - * A proprietary ID can also be defined - * locally (\c \#define) if the needed - * one hasn't been registered. - * \param[in] key_select Indicates which key to use to sign. - * \param[in] hash_to_sign The bytes to sign. Typically, a hash of - * a payload. - * \param[in] signature_buffer Pointer and length of buffer into which - * the resulting signature is put. - * \param[in] signature Pointer and length of the signature - * returned. - * - * \retval T_COSE_SUCCESS - * Successfully created the signature. - * \retval T_COSE_ERR_SIG_BUFFER_SIZE - * The \c signature_buffer too small. - * \retval T_COSE_ERR_UNSUPPORTED_SIGNING_ALG - * The requested signing algorithm, \c cose_alg_id, is not - * supported. - * \retval T_COSE_ERR_UNKNOWN_KEY - * The key identified by \c key_select was not found. - * \retval T_COSE_ERR_WRONG_TYPE_OF_KEY - * The key was found, but it was the wrong type. - * \retval T_COSE_ERR_INVALID_ARGUMENT - * Some (unspecified) argument was not valid. - * \retval T_COSE_ERR_INSUFFICIENT_MEMORY - * Insufficient heap memory. - * \retval T_COSE_ERR_FAIL - * General unspecific failure. - * \retval T_COSE_ERR_TAMPERING_DETECTED - * Equivalent to \c PSA_ERROR_TAMPERING_DETECTED. - * - * This is called to do public key signing. The implementation will - * vary from one platform / OS to another but should conform to the - * description here. - * - * The key selection depends on the platform / OS. - * - * See the note in the Detailed Description (the \\file comment block) - * for details on how \c useful_buf and \c useful_buf_c are used to - * return the signature. - * - * To find out the size of the signature buffer needed, call this with - * \c signature_buffer->ptr \c NULL and \c signature_buffer->len a - * very large number like \c UINT32_MAX. The size will be returned in - * \c signature->len. - */ -enum t_cose_err_t -t_cose_crypto_pub_key_sign(int32_t cose_alg_id, - int32_t key_select, - struct useful_buf_c hash_to_sign, - struct useful_buf signature_buffer, - struct useful_buf_c *signature); - - -/** - * \brief perform public key signature verification. Part of the - * t_cose crypto adaptation layer. - * - * \param[in] cose_alg_id The algorithm to use for verification. - * The IDs are defined in [COSE (RFC 8152)] - * (https://tools.ietf.org/html/rfc8152) - * or in the [IANA COSE Registry] - * (https://www.iana.org/assignments/cose/cose.xhtml). - * A proprietary ID can also be defined - * locally (\c \#define) if the needed one - * hasn't been registered. - * \param[in] key_select Verification key selection. - * \param[in] key_id A key id or \c NULL_USEFUL_BUF_C. - * \param[in] hash_to_verify The data or hash that is to be verified. - * \param[in] signature The signature. - * - * This verifies that the \c signature passed in was over the \c - * hash_to_verify passed in. - * - * The public key used to verify the signature is selected by the \c - * key_id if it is not \c NULL_USEFUL_BUF_C or the \c key_select if it - * is. - * - * The key selected must be, or include, a public key of the correct - * type for \c cose_alg_id. - * - * \retval T_COSE_SUCCESS - * The signature is valid - * \retval T_COSE_ERR_SIG_VERIFY - * Signature verification failed. For example, the - * cryptographic operations completed successfully but hash - * wasn't as expected. - * \retval T_COSE_ERR_UNKNOWN_KEY - * The key identified by \c key_select or a \c kid was - * not found. - * \retval T_COSE_ERR_WRONG_TYPE_OF_KEY - * The key was found, but it was the wrong type - * for the operation. - * \retval T_COSE_ERR_UNSUPPORTED_SIGNING_ALG - * The requested signing algorithm is not supported. - * \retval T_COSE_ERR_INVALID_ARGUMENT - * Some (unspecified) argument was not valid. - * \retval T_COSE_ERR_INSUFFICIENT_MEMORY - * Out of heap memory. - * \retval T_COSE_ERR_FAIL - * General unspecific failure. - * \retval T_COSE_ERR_TAMPERING_DETECTED - * Equivalent to \c PSA_ERROR_TAMPERING_DETECTED. - */ -enum t_cose_err_t -t_cose_crypto_pub_key_verify(int32_t cose_alg_id, - int32_t key_select, - struct useful_buf_c key_id, - struct useful_buf_c hash_to_verify, - struct useful_buf_c signature); - - -/** - * The size of X and Y coordinate in 2 parameter style EC public - * key. Format is as defined in [COSE (RFC 8152)] - * (https://tools.ietf.org/html/rfc8152) and [SEC 1: Elliptic Curve - * Cryptography](http://www.secg.org/sec1-v2.pdf). - * - * This size is well-known and documented in public standards. - */ -#define T_COSE_CRYPTO_EC_P256_COORD_SIZE 32 - - -/** - * \brief Get an elliptic curve public key. Part of the t_cose crypto - * adaptation layer. - * - * \param[in] key_select Used to look up the public - * key to return when \c kid is - * \c NULL_USEFUL_BUF_C. - * \param[in] kid A key ID to look up against. May be - * \c NULL_USEFUL_BUF_C. This is typically - * the kid from the COSE unprotected header. - * \param[out] cose_curve_id The curve ID of the key returned as - * defined by [COSE (RFC 8152)] - * (https://tools.ietf.org/html/rfc8152) - * or the IANA COSE registry. - * \param[in] buf_to_hold_x_coord Pointer and length into which the - * X coordinate is put. - * \param[in] buf_to_hold_y_coord Pointer and length into which the - * Y coordinate is put. - * \param[out] x_coord Pointer and length of the returned X - * coordinate. - * \param[out] y_coord Pointer and length of the returned Y - * coordinate. - * - * \retval T_COSE_SUCCESS - * The key was found and is returned. - * \retval T_COSE_ERR_UNKNOWN_KEY - * The key identified by \c key_select or a \c kid was not - * found. - * \retval T_COSE_ERR_WRONG_TYPE_OF_KEY - * The key was found, but it was the wrong type for the - * operation. - * \retval T_COSE_ERR_FAIL - * General unspecific failure. - * \retval T_COSE_ERR_KEY_BUFFER_SIZE - * Buffer to hold the output was too small. - * - * This finds and returns a public key. Where it looks for the key is - * dependent on the OS / platform. - * - * \ref T_COSE_CRYPTO_EC_P256_COORD_SIZE is the size of the X or Y - * coordinate for the NIST P-256 curve. - * - * See the note in the Detailed Description (the \\file comment block) - * for details on how \c useful_buf and \c useful_buf_c are used to - * return the X and Y coordinates. - */ -enum t_cose_err_t -t_cose_crypto_get_ec_pub_key(int32_t key_select, - struct useful_buf_c kid, - int32_t *cose_curve_id, - struct useful_buf buf_to_hold_x_coord, - struct useful_buf buf_to_hold_y_coord, - struct useful_buf_c *x_coord, - struct useful_buf_c *y_coord); - - -/* - * No function to get private key because there is no need for it. - * The private signing key only needs to exist behind - * t_cose_crypto_pub_key_sign(). - */ - - - - -/** - * The context for use with the hash adaptation layer here. - */ -struct t_cose_crypto_hash { - /* Can't put the actual size here without creating dependecy on - * actual hash implementation, so this is a fairly large and - * accommodating size. - */ - uint8_t bytes[280]; -}; - - -/** - * The size of the output of SHA-256 in bytes. - * - * (It is safe to define this independently here as its size is - * well-known and fixed. There is no need to reference - * platform-specific headers and incur messy dependence.) - */ -#define T_COSE_CRYPTO_SHA256_SIZE 32 - - -/** - * \brief Start cryptographic hash. Part of the t_cose crypto - * adaptation layer. - * - * \param[in,out] hash_ctx Pointer to the hash context that - * will be initialized. - * \param[in] cose_hash_alg_id Algorithm ID that identifies the - * hash to use. This is from the - * [IANA COSE Registry] - * (https://www.iana.org/assignments/cose/cose.xhtml). - * As of the creation of this interface - * no identifiers of only a hash - * functions have been registered. - * Signature algorithms that include - * specification of the hash have been - * registered, but they are not to be - * used here. Until hash functions only - * have been officially registered, some - * IDs are defined in the proprietary - * space in t_cose_common.h. - * - * \retval T_COSE_ERR_UNSUPPORTED_HASH - * The requested algorithm is unknown or unsupported. - * - * \retval T_COSE_ERR_HASH_GENERAL_FAIL - * Some general failure of the hash function - * - * This initializes the hash context for the particular algorithm. It - * must be called first. A \c hash_ctx can be reused if it is - * reinitialized. - */ -enum t_cose_err_t -t_cose_crypto_hash_start(struct t_cose_crypto_hash *hash_ctx, - int32_t cose_hash_alg_id); - - -/** - * \brief Feed data into a cryptographic hash. Part of the t_cose - * crypto adaptation layer. - * - * \param[in,out] hash_ctx Pointer to the hash context in which - * accumulate the hash. - * \param[in] data_to_hash Pointer and length of data to feed into - * hash. The pointer may by \c NULL in which - * case no hashing is performed. - * - * There is no return value. If an error occurs it is remembered in \c - * hash_ctx and returned when t_cose_crypto_hash_finish() is called. - * Once in the error state, this function may be called, but it will - * not do anything. - */ -void t_cose_crypto_hash_update(struct t_cose_crypto_hash *hash_ctx, - struct useful_buf_c data_to_hash); - - -/** - * \brief Finish a cryptographic hash. Part of the t_cose crypto - * adaptation layer. - * - * \param[in,out] hash_ctx Pointer to the hash context. - * \param[in] buffer_to_hold_result Pointer and length into which - * the resulting hash is put. - * \param[out] hash_result Pointer and length of the - * resulting hash. - * - * \retval T_COSE_ERR_HASH_GENERAL_FAIL - * Some general failure of the hash function. - * \retval T_COSE_ERR_HASH_BUFFER_SIZE - * The size of the buffer to hold the hash result was - * too small. - * - * Call this to complete the hashing operation. If the everything - * completed correctly, the resulting hash is returned. Note that any - * errors that occurred during t_cose_crypto_hash_update() are - * returned here. - * - * See the note in the Detailed Description (the \\file comment block) - * for details on how \c useful_buf and \c useful_buf_c are used to - * return the hash. - */ -enum t_cose_err_t -t_cose_crypto_hash_finish(struct t_cose_crypto_hash *hash_ctx, - struct useful_buf buffer_to_hold_result, - struct useful_buf_c *hash_result); - - - -/* - * Public inline function. See documentation above. - */ -static inline size_t t_cose_signature_size(int32_t cose_sig_alg_id) -{ - switch(cose_sig_alg_id) { - case COSE_ALGORITHM_ES256: - return T_COSE_EC_P256_SIG_SIZE; - default: - return T_COSE_EC_P256_SIG_SIZE; - } -} - - -#endif /* __T_COSE_CRYPTO_H__ */ diff --git a/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/t_cose/src/t_cose_defines.h b/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/t_cose/src/t_cose_defines.h deleted file mode 100644 index e2cc970..0000000 --- a/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/t_cose/src/t_cose_defines.h +++ /dev/null @@ -1,291 +0,0 @@ -/* - * t_cose_defines.h - * - * Copyright (c) 2018-2019, Laurence Lundblade. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - * - * See BSD-3-Clause license in README.md - */ - -#ifndef __T_COSE_DEFINES_H__ -#define __T_COSE_DEFINES_H__ - -/** - * \file t_cose_defines.h - * - * \brief Constants from COSE standard and IANA registry. - * - * This file contains constants identifiers defined in [COSE (RFC - * 8152)] (https://tools.ietf.org/html/rfc8152) and [IANA COSE - * Registry] (https://www.iana.org/assignments/cose/cose.xhtml). They - * include algorithm IDs and other constants. - * - * Many constants in the IANA registry are not included here yet as - * they are not needed by t_cose. They can be added if they become - * needed. - */ - - - - -/* --------------- COSE Header parameters ----------- - * https://www.iana.org/assignments/cose/cose.xhtml#header-parameters - */ - -/** - * \def COSE_HEADER_PARAM_ALG - * - * \brief Label of COSE header that indicates an algorithm. - */ -#define COSE_HEADER_PARAM_ALG 1 - -/** - * \def COSE_HEADER_PARAM_KID - * - * \brief Label of COSE header that contains a key ID. - */ -#define COSE_HEADER_PARAM_KID 4 - - - - -/* ------------ COSE Header Algorithm Parameters -------------- - * https://www.iana.org/assignments/cose/cose.xhtml#header-algorithm-parameters - * - * None of these are defined here yet, as they are not needed by t_cose yet. - */ - - - - -/* ------------- COSE Algorithms ---------------------------- - * https://www.iana.org/assignments/cose/cose.xhtml#algorithms - */ - -/** - * \def COSE_ALGORITHM_ES256 - * - * \brief Indicates ECDSA with SHA-256. - * - * Value for \ref COSE_HEADER_PARAM_ALG to indicate ECDSA. w/SHA-256 - */ -#define COSE_ALGORITHM_ES256 -7 - -/** - * \def COSE_ALGORITHM_ES384 - * - * \brief Indicates ECDSA with SHA-384. - * - * Value for \ref COSE_HEADER_PARAM_ALG to indicate ECDSA. w/SHA-384 - */ -#define COSE_ALGORITHM_ES384 -35 - -/** - * \def COSE_ALGORITHM_ES512 - * - * \brief Indicates ECDSA with SHA-384. - * - * Value for \ref COSE_HEADER_PARAM_ALG to indicate ECDSA. w/SHA-512 - */ -#define COSE_ALGORITHM_ES512 -36 - - -/** - * \def COSE_ALG_SHA256_PROPRIETARY - * - * \brief COSE-style algorithm ID for SHA256. The official COSE - * algorithm registry doesn't yet define an ID for a pure hash - * function. One is needed for internal use, so this is defined. - * - * This is only used internally in the implementation and doesn't - * appear in any protocol messages so there are no interoperability - * issues. When this gets defined in the IANA registry, that value can - * be substituted here and all will work fine. - */ -#define COSE_ALG_SHA256_PROPRIETARY -72000 - - - - -/* ---------- COSE Key Common Parameters -------------- - * https://www.iana.org/assignments/cose/cose.xhtml#key-common-parameters - */ - -/** - * \def COSE_KEY_COMMON_KTY - * - * \brief Label for data item containing the key type. - * - * In a \c COSE_Key, label that indicates the data item containing the - * key type. - */ -#define COSE_KEY_COMMON_KTY 1 - -/** - * \def COSE_KEY_COMMON_KID - * - * \brief Label for data item containing the key's kid. - * - * In a \c COSE_Key, label that indicates the data item containing the - * kid of this key. - */ -#define COSE_KEY_COMMON_KID 2 - - - - -/* ---------- COSE Key Type Parameters -------------------- - * https://www.iana.org/assignments/cose/cose.xhtml#key-type-parameters - */ - -/** - * \def COSE_KEY_PARAM_CRV - * - * \brief Label for data item indicating EC curve. - * - * In a \c COSE_Key that holds an EC key of either type \ref - * COSE_KEY_TYPE_EC2 or \ref COSE_KEY_TYPE_OKP this labels the data - * item with the EC curve for the key. - */ -#define COSE_KEY_PARAM_CRV -1 - -/** - * \def COSE_KEY_PARAM_X_COORDINATE - * - * \brief Label for data item that is an X coordinate of an EC key. - * - * In a \c COSE_Key that holds an EC key, this is label that indicates - * the data item containing the X coordinate. - * - * This is used for both key types \ref COSE_KEY_TYPE_EC2 and \ref - * COSE_KEY_TYPE_OKP. - */ -#define COSE_KEY_PARAM_X_COORDINATE -2 - -/** - * \def COSE_KEY_PARAM_Y_COORDINATE - * - * \brief Label for data item that is a y coordinate of an EC key. - * - * In a COSE_Key that holds an EC key, this is label that indicates - * the data item containing the Y coordinate. - * - * This is used only for key type \ref COSE_KEY_TYPE_EC2. - */ -#define COSE_KEY_PARAM_Y_COORDINATE -3 - -/** - * \def COSE_KEY_PARAM_PRIVATE_D - * - * \brief Label for data item that is d, the private part of EC key. - * - * In a \c COSE_Key that holds an EC key, this is label that indicates - * the data item containing the Y coordinate. - * - * This is used for both key types \ref COSE_KEY_TYPE_EC2 and \ref - * COSE_KEY_TYPE_OKP. - */ -#define COSE_KEY_PARAM_PRIVATE_D -4 - - - - -/* ---------- COSE Key Types -------------------------------- - * https://www.iana.org/assignments/cose/cose.xhtml#key-type - */ - -/** - * \def COSE_KEY_TYPE_OKP - * - * \brief Key type is Octet Key Pair - * - * In a \c COSE_Key, this is a value of the data item labeled \ref - * COSE_KEY_COMMON_KTY that indicates the \c COSE_Key is some sort of - * key pair represented by some octets. It may or may not be an EC - * key. - */ -#define COSE_KEY_TYPE_OKP 1 - -/** - * \def COSE_KEY_TYPE_EC2 - * - * \brief Key is a 2-parameter EC key. - * - * In a \c COSE_Key, this is a value of the data item labeled \ref - * COSE_KEY_COMMON_KTY that indicates the \c COSE_Key is an EC key - * specified with two coordinates, X and Y. - */ -#define COSE_KEY_TYPE_EC2 2 - -/** - * \def COSE_KEY_TYPE_SYMMETRIC - * - * \brief Key is a symmetric key. - * - * In a \c COSE_Key, this is a value of the data item labeled \ref - * COSE_KEY_COMMON_KTY that indicates the \c COSE_Key is a symmetric - * key. - */ -#define COSE_KEY_TYPE_SYMMETRIC 4 - - - - -/* ----------- COSE Elliptic Curves --------------------- - * https://www.iana.org/assignments/cose/cose.xhtml#elliptic-curves - */ - -/** - * \def COSE_ELLIPTIC_CURVE_P_256 - * - * \brief Key type for NIST P-256 key - * - * In a \c COSE_Key, this is a value of the data item labeled \ref - * COSE_KEY_PARAM_CRV to indicate the NIST P-256 curve, also known as - * secp256r1. - * - * This key type is always \ref COSE_KEY_TYPE_EC2. - */ -#define COSE_ELLIPTIC_CURVE_P_256 1 - -/** - * \def COSE_ELLIPTIC_CURVE_P_384 - * - * \brief Key type for NIST P-384 key - * - * In a \c COSE_Key, this is a value of the data item labeled \ref - * COSE_KEY_PARAM_CRV to indicate the NIST P-384 curve, also known as - * secp384r1. - * - * This key type is always \ref COSE_KEY_TYPE_EC2. - */ -#define COSE_ELLIPTIC_CURVE_P_384 2 - -/** - * \def COSE_ELLIPTIC_CURVE_P_521 - * - * \brief Key type for NIST P-521 key - * - * In a \c COSE_Key, this is a value of the data item labeled \ref - * COSE_KEY_PARAM_CRV to indicate the NIST P-521 curve, also known as - * secp521r1. - */ -#define COSE_ELLIPTIC_CURVE_P_521 3 - - - - -/* ------- Constants from RFC 8152 --------- - */ - -/** - * \def COSE_SIG_CONTEXT_STRING_SIGNATURE1 - * - * \brief This is a string constant used by COSE to label \c COSE_Sign1 - * structures. See RFC 8152, section 4.4. - */ -#define COSE_SIG_CONTEXT_STRING_SIGNATURE1 "Signature1" - - -#endif /* __T_COSE_DEFINES_H__ */ diff --git a/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/t_cose/src/t_cose_sign1_sign.c b/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/t_cose/src/t_cose_sign1_sign.c deleted file mode 100644 index 8f55bc0..0000000 --- a/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/t_cose/src/t_cose_sign1_sign.c +++ /dev/null @@ -1,499 +0,0 @@ -/* - * t_cose_sign1_sign.c - * - * Copyright (c) 2018-2019, Laurence Lundblade. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - * - * See BSD-3-Clause license in README.md - */ - -#include "t_cose_sign1_sign.h" -#include "qcbor.h" -#include "t_cose_defines.h" -#include "t_cose_crypto.h" -#include "t_cose_util.h" - - -/** - * \file t_cose_sign1_sign.c - * - * \brief This implements t_cose signing - */ - - -/** - * \brief Create a short-circuit signature - * - * \param[in] cose_alg_id Algorithm ID. This is used only to make - * the short-circuit signature the same size - * as the real signature would be for the - * particular algorithm. - * \param[in] hash_to_sign The bytes to sign. Typically, a hash of - * a payload. - * \param[in] signature_buffer Pointer and length of buffer into which - * the resulting signature is put. - * \param[in] signature Pointer and length of the signature - * returned. - * - * \return This returns one of the error codes defined by \ref t_cose_err_t. - * - * This creates the short-circuit signature that is a concatenation of - * hashes up to the expected size of the signature. This is a test - * mode only has it has no security value. This is retained in - * commercial production code as a useful test or demo that can run - * even if key material is not set up or accessible. - */ -static inline enum t_cose_err_t -short_circuit_sign(int32_t cose_alg_id, - struct useful_buf_c hash_to_sign, - struct useful_buf signature_buffer, - struct useful_buf_c *signature) -{ - /* approximate stack use on 32-bit machine: local use: 16 - */ - enum t_cose_err_t return_value; - size_t array_indx; - size_t amount_to_copy; - size_t sig_size; - - sig_size = t_cose_signature_size(cose_alg_id); - - if(sig_size > signature_buffer.len) { - /* Buffer too small for this signature type */ - return_value = T_COSE_ERR_SIG_BUFFER_SIZE; - goto Done; - } - - /* Loop concatening copies of the hash to fill out to signature size */ - for(array_indx = 0; array_indx < sig_size; array_indx += hash_to_sign.len) { - amount_to_copy = sig_size - array_indx; - if(amount_to_copy > hash_to_sign.len) { - amount_to_copy = hash_to_sign.len; - } - memcpy((uint8_t *)signature_buffer.ptr + array_indx, - hash_to_sign.ptr, - amount_to_copy); - } - signature->ptr = signature_buffer.ptr; - signature->len = sig_size; - return_value = T_COSE_SUCCESS; - -Done: - return return_value; -} - - - -/** - * The maximum size of a CBOR Encoded \c COSE_Key that this - * implementation can handle. \c COSE_Key is the serialization format - * for public and other types of keys defined by [COSE (RFC 8152)] - * (https://tools.ietf.org/html/rfc8152). - * - * This can be increased to handle larger keys, but stack usage will - * go up with this increase. - */ -#define MAX_ENCODED_COSE_KEY_SIZE \ - 1 + /* 1 byte to encode map */ \ - 2 + /* 2 bytes to encode key type */ \ - 2 + /* 2 bytes to encode curve */ \ - 2 * /* the X and Y coordinates at 32 bytes each */ \ - (T_COSE_CRYPTO_EC_P256_COORD_SIZE + 1 + 2) - - -/** - * \brief CBOR encode a public key as a \c COSE_Key - * - * \param[in] key_select Identifies the public key to encode. - * - * \param[in] buffer_for_cose_key Pointer and length of buffer into which - * the encoded \c COSE_Key is put. - * \param[in] cose_key Pointer and length of the encoded \c COSE_Key. - * - * \return This returns one of the error codes defined by \ref t_cose_err_t. - * - * \c COSE_Key is the COSE-defined format for serializing a key for - * transmission in a protocol. This function encodes an EC public key - * expressed as an X and Y coordinate. - */ -static enum t_cose_err_t -t_cose_encode_cose_key(int32_t key_select, - struct useful_buf buffer_for_cose_key, - struct useful_buf_c *cose_key) -{ - /* approximate stack use on 32-bit machine: - * local use: 328 - * with calls: 370 - */ - enum t_cose_err_t return_value; - QCBORError qcbor_result; - QCBOREncodeContext cbor_encode_ctx; - USEFUL_BUF_MAKE_STACK_UB( buffer_for_x_coord, - T_COSE_CRYPTO_EC_P256_COORD_SIZE); - USEFUL_BUF_MAKE_STACK_UB( buffer_for_y_coord, - T_COSE_CRYPTO_EC_P256_COORD_SIZE); - struct useful_buf_c x_coord; - struct useful_buf_c y_coord; - int32_t cose_curve_id; - struct useful_buf_c encoded_key_id; - - /* Get the public key x and y */ - return_value = t_cose_crypto_get_ec_pub_key(key_select, - NULL_USEFUL_BUF_C, - &cose_curve_id, - buffer_for_x_coord, - buffer_for_y_coord, - &x_coord, - &y_coord); - if(return_value != T_COSE_SUCCESS) { - goto Done; - } - - /* Encode it into a COSE_Key structure */ - QCBOREncode_Init(&cbor_encode_ctx, buffer_for_cose_key); - QCBOREncode_OpenMap(&cbor_encode_ctx); - QCBOREncode_AddInt64ToMapN(&cbor_encode_ctx, - COSE_KEY_COMMON_KTY, - COSE_KEY_TYPE_EC2); - QCBOREncode_AddInt64ToMapN(&cbor_encode_ctx, - COSE_KEY_PARAM_CRV, - cose_curve_id); - QCBOREncode_AddBytesToMapN(&cbor_encode_ctx, - COSE_KEY_PARAM_X_COORDINATE, - x_coord); - QCBOREncode_AddBytesToMapN(&cbor_encode_ctx, - COSE_KEY_PARAM_Y_COORDINATE, - y_coord); - QCBOREncode_CloseMap(&cbor_encode_ctx); - - qcbor_result = QCBOREncode_Finish(&cbor_encode_ctx, &encoded_key_id); - if(qcbor_result != QCBOR_SUCCESS) { - /* Mainly means that the COSE_Key was too big for buffer_for_cose_key */ - return_value = T_COSE_ERR_PROTECTED_HEADERS; - goto Done; - } - - /* Finish up and return */ - *cose_key = encoded_key_id; - return_value = T_COSE_SUCCESS; - -Done: - return return_value; -} - - -/** - * \brief SHA-256 hash a buffer in one quick function - * - * \param[in] bytes_to_hash The bytes to be hashed. - * - * \param[in] buffer_for_hash Pointer and length into which - * the resulting hash is put. - * \param[out] hash Pointer and length of the - * resulting hash. - * \return This returns one of the error codes defined by \ref t_cose_err_t. - * - * Simple wrapper for start, update and finish interface to a hash. - * - * Having this as a separate function helps keep stack usage down and - * is convenient. - */ -static enum t_cose_err_t quick_sha256(struct useful_buf_c bytes_to_hash, - struct useful_buf buffer_for_hash, - struct useful_buf_c *hash) -{ - /* approximate stack use on 32-bit machine: - local use: 132 - */ - enum t_cose_err_t return_value = 0; - struct t_cose_crypto_hash hash_ctx; - - return_value = t_cose_crypto_hash_start(&hash_ctx, - COSE_ALG_SHA256_PROPRIETARY); - if(return_value) { - goto Done; - } - t_cose_crypto_hash_update(&hash_ctx, bytes_to_hash); - return_value = t_cose_crypto_hash_finish(&hash_ctx, - buffer_for_hash, - hash); - -Done: - return return_value; -} - - -/** - * \brief Make a key ID based on the public key to go in the kid - * unprotected header. - * - * \param[in] key_select Identifies the public key. - * \param[in] buffer_for_key_id Pointer and length into which - * the resulting key ID is put. - * \param[out] key_id Pointer and length of the - * resulting key ID. - * - * \return This returns one of the error codes defined by \ref t_cose_err_t. - * - * - * See t_cose_sign1_init() for documentation of the key ID format - * created here. - */ -static inline enum t_cose_err_t get_keyid(int32_t key_select, - struct useful_buf buffer_for_key_id, - struct useful_buf_c *key_id) -{ - /* approximate stack use on 32-bit machine: - * local use: 100 - * with calls inlined: 560 - * with calls not inlined: 428 - */ - enum t_cose_err_t return_value; - USEFUL_BUF_MAKE_STACK_UB( buffer_for_cose_key, - MAX_ENCODED_COSE_KEY_SIZE); - struct useful_buf_c cose_key; - - /* Doing the COSE encoding and the hashing in separate functions - * called from here reduces the stack usage in this function by a - * lot - */ - - /* Get the key and encode it as a COSE_Key */ - return_value = t_cose_encode_cose_key(key_select, - buffer_for_cose_key, - &cose_key); - if(return_value != T_COSE_SUCCESS) { - goto Done; - } - - /* SHA256 hash of it is all we care about in the end */ - return_value = quick_sha256(cose_key, buffer_for_key_id, key_id); - -Done: - return return_value; -} - - -/** - * \brief Makes the protected headers for COSE. - * - * \param[in] cose_alg_id The COSE algorithm ID to put in the headers. - * - * \param[in] buffer_for_header Pointer and length into which - * the resulting encoded protected - * headers is put. - * - * \return The pointer and length of the protected headers is - * returned, or \c NULL_USEFUL_BUF_C if this fails. - * - * The protected headers are returned in fully encoded CBOR format as - * they are added to the \c COSE_Sign1 as a binary string. This is - * different from the unprotected headers which are not handled this - * way. - * - * This returns \c NULL_USEFUL_BUF_C if buffer_for_header was too - * small. See also definition of \ref T_COSE_SIGN1_MAX_PROT_HEADER - */ -static inline struct useful_buf_c -make_protected_header(int32_t cose_alg_id, - struct useful_buf buffer_for_header) -{ - /* approximate stack use on 32-bit machine: - * local use: 170 - * with calls: 210 - */ - struct useful_buf_c protected_headers; - QCBORError qcbor_result; - QCBOREncodeContext cbor_encode_ctx; - struct useful_buf_c return_value; - - QCBOREncode_Init(&cbor_encode_ctx, buffer_for_header); - QCBOREncode_OpenMap(&cbor_encode_ctx); - QCBOREncode_AddInt64ToMapN(&cbor_encode_ctx, - COSE_HEADER_PARAM_ALG, - cose_alg_id); - QCBOREncode_CloseMap(&cbor_encode_ctx); - qcbor_result = QCBOREncode_Finish(&cbor_encode_ctx, &protected_headers); - - if(qcbor_result == QCBOR_SUCCESS) { - return_value = protected_headers; - } else { - return_value = NULL_USEFUL_BUF_C; - } - - return return_value; -} - - -/** - * \brief Add the unprotected headers to a CBOR encoding context - * - * \param[in] cbor_encode_ctx CBOR encoding context to output to - * \param[in] kid The key ID to go into the kid header. - * - * No error is returned. If an error occurred it will be returned when - * \c QCBOR_Finish() is called on \c cbor_encode_ctx. - * - * The unprotected headers added by this are just the key ID - */ -static inline void add_unprotected_headers(QCBOREncodeContext *cbor_encode_ctx, - struct useful_buf_c kid) -{ - QCBOREncode_OpenMap(cbor_encode_ctx); - QCBOREncode_AddBytesToMapN(cbor_encode_ctx, COSE_HEADER_PARAM_KID, kid); - QCBOREncode_CloseMap(cbor_encode_ctx); -} - - -/* - * Public function. See t_cose_sign1_sign.h - */ -enum t_cose_err_t t_cose_sign1_init(struct t_cose_sign1_ctx *me, - bool short_circuit_sign, - int32_t cose_alg_id, - int32_t key_select, - QCBOREncodeContext *cbor_encode_ctx) -{ - /* approximate stack use on 32-bit machine: - * local use: 66 - * with calls inlined: 900 - * with calls not inlined: 500 - */ - - int32_t hash_alg; - enum t_cose_err_t return_value; - USEFUL_BUF_MAKE_STACK_UB( buffer_for_kid, T_COSE_CRYPTO_SHA256_SIZE); - struct useful_buf_c kid; - struct useful_buf buffer_for_protected_header; - - /* Check the cose_alg_id now by getting the hash alg as an early - error check even though it is not used until later. */ - hash_alg = hash_alg_id_from_sig_alg_id(cose_alg_id); - if(hash_alg == INT32_MAX) { - return T_COSE_ERR_UNSUPPORTED_SIGNING_ALG; - } - - /* Remember all the parameters in the context */ - me->cose_algorithm_id = cose_alg_id; - me->key_select = key_select; - me->short_circuit_sign = short_circuit_sign; - me->cbor_encode_ctx = cbor_encode_ctx; - - /* Get the key id because it goes into the headers that are about - to be made. */ - if(short_circuit_sign) { - return_value = get_short_circuit_kid(buffer_for_kid, &kid); - } else { - return_value = get_keyid(key_select, buffer_for_kid, &kid); - } - if(return_value) { - goto Done; - } - - /* Get started with the tagged array that holds the four parts of - a cose single signed message */ - QCBOREncode_AddTag(cbor_encode_ctx, CBOR_TAG_COSE_SIGN1); - QCBOREncode_OpenArray(cbor_encode_ctx); - - /* The protected headers, which are added as a wrapped bstr */ - buffer_for_protected_header = - USEFUL_BUF_FROM_BYTE_ARRAY(me->buffer_for_protected_headers); - me->protected_headers = make_protected_header(cose_alg_id, - buffer_for_protected_header); - if(useful_buf_c_is_null(me->protected_headers)) { - /* The sizing of storage for protected headers is - off (should never happen in tested, released code) */ - return_value = T_COSE_SUCCESS; - goto Done; - } - QCBOREncode_AddBytes(cbor_encode_ctx, me->protected_headers); - - /* The Unprotected headers */ - add_unprotected_headers(cbor_encode_ctx, kid); - - /* Any failures in CBOR encoding will be caught in finish - when the CBOR encoding is closed off. No need to track - here as the CBOR encoder tracks it internally. */ - - return_value = T_COSE_SUCCESS; - -Done: - return return_value; -} - - -/* - * Public function. See t_cose_sign1_sign.h - */ -enum t_cose_err_t t_cose_sign1_finish(struct t_cose_sign1_ctx *me, - struct useful_buf_c signed_payload) -{ - /* approximate stack use on 32-bit machine: - * local use: 116 - * with calls inline: 500 - * with calls not inlined; 450 - */ - enum t_cose_err_t return_value; - /* pointer and length of the completed tbs hash */ - struct useful_buf_c tbs_hash; - /* Pointer and length of the completed signature */ - struct useful_buf_c signature; - /* Buffer for the actual signature */ - USEFUL_BUF_MAKE_STACK_UB( buffer_for_signature, - T_COSE_MAX_EC_SIG_SIZE); - /* Buffer for the tbs hash. Only big enough for SHA256 */ - USEFUL_BUF_MAKE_STACK_UB( buffer_for_tbs_hash, - T_COSE_CRYPTO_SHA256_SIZE); - - /* Create the hash of the to-be-signed bytes. Inputs to the hash - * are the protected headers, the payload that getting signed, the - * cose signature alg from which the hash alg is determined. The - * cose_algorithm_id was checked in t_cose_sign1_init() so it - * doesn't need to be checked here. - */ - return_value = create_tbs_hash(me->cose_algorithm_id, - buffer_for_tbs_hash, - &tbs_hash, - me->protected_headers, - signed_payload); - if(return_value) { - goto Done; - } - - /* Compute the signature using public key crypto. The key selector - * and algorithm ID are passed in to know how and what to sign - * with. The hash of the TBS bytes are what is signed. A buffer in - * which to place the signature is passed in and the signature is - * returned. - * - * Short-circuit signing is invoked if requested. It does no - * public key operation and requires no key. It is just a test - * mode that always works. - */ - if(me->short_circuit_sign) { - return_value = short_circuit_sign(me->cose_algorithm_id, - tbs_hash, - buffer_for_signature, - &signature); - } else { - return_value = t_cose_crypto_pub_key_sign(me->cose_algorithm_id, - me->key_select, - tbs_hash, - buffer_for_signature, - &signature); - } - if(return_value) { - goto Done; - } - - /* Add signature to CBOR and close out the array */ - QCBOREncode_AddBytes(me->cbor_encode_ctx, signature); - QCBOREncode_CloseArray(me->cbor_encode_ctx); - - /* CBOR encoding errors are tracked in the CBOR encoding context - and handled in the layer above this */ - -Done: - return return_value; -} diff --git a/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/t_cose/src/t_cose_util.c b/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/t_cose/src/t_cose_util.c deleted file mode 100644 index ba4910e..0000000 --- a/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/t_cose/src/t_cose_util.c +++ /dev/null @@ -1,189 +0,0 @@ -/* - * t_cose_util.c - * - * Copyright 2019, Laurence Lundblade - * - * SPDX-License-Identifier: BSD-3-Clause - * - * See BSD-3-Clause license in README.mdE. - */ - -#include "t_cose_util.h" -#include "qcbor.h" -#include "t_cose_defines.h" -#include "t_cose_common.h" -#include "t_cose_crypto.h" - - -/** - * \file t_cose_util.c - * - * \brief Implementation of t_cose utility functions. - * - */ - - -/* - * Public function. See t_cose_util.h - */ -int32_t hash_alg_id_from_sig_alg_id(int32_t cose_sig_alg_id) -{ - /* if other hashes, particularly those that output bigger hashes - * are added here, various other parts of this code have to be - * changed to have larger buffers. - */ - switch(cose_sig_alg_id) { - - case COSE_ALGORITHM_ES256: - return COSE_ALG_SHA256_PROPRIETARY; - - default: - return INT32_MAX; - } -} - - -/* - * Format of to-be-signed bytes used by create_tbs_hash(). - * This is defined in COSE (RFC 8152). It is the input - * to the hash. - * - * Sig_structure = [ - * context : "Signature" / "Signature1" / "CounterSignature", - * body_protected : empty_or_serialized_map, - * ? sign_protected : empty_or_serialized_map, - * external_aad : bstr, - * payload : bstr - * ] - */ - - -/** - * This is the size of the first part of the CBOR encoded TBS - * bytes. It is around 20 bytes. See create_tbs_hash(). - */ -#define T_COSE_SIZE_OF_TBS \ - 1 + /* For opening the array */ \ - sizeof(COSE_SIG_CONTEXT_STRING_SIGNATURE1) + /* "Signature1" */ \ - 2 + /* Overhead for encoding string */ \ - T_COSE_SIGN1_MAX_PROT_HEADER + /* entire protected headers */ \ - 3 * ( /* 3 NULL bstrs for fields not used */ \ - 1 /* size of a NULL bstr */ \ - ) - - -/* - * Public function. See t_cose_util.h - */ -enum t_cose_err_t create_tbs_hash(int32_t cose_alg_id, - struct useful_buf buffer_for_hash, - struct useful_buf_c *hash, - struct useful_buf_c protected_headers, - struct useful_buf_c payload) -{ - /* approximate stack use on 32-bit machine: - * local use: 320 - * with calls: 360 - */ - enum t_cose_err_t return_value; - QCBOREncodeContext cbor_encode_ctx; - UsefulBuf_MAKE_STACK_UB( buffer_for_TBS_first_part, T_COSE_SIZE_OF_TBS); - struct useful_buf_c tbs_first_part; - QCBORError qcbor_result; - struct t_cose_crypto_hash hash_ctx; - int32_t hash_alg_id; - - /* This builds the CBOR-format to-be-signed bytes */ - QCBOREncode_Init(&cbor_encode_ctx, buffer_for_TBS_first_part); - QCBOREncode_OpenArray(&cbor_encode_ctx); - /* context */ - QCBOREncode_AddSZString(&cbor_encode_ctx, - COSE_SIG_CONTEXT_STRING_SIGNATURE1); - /* body_protected */ - QCBOREncode_AddBytes(&cbor_encode_ctx, - protected_headers); - /* sign_protected */ - QCBOREncode_AddBytes(&cbor_encode_ctx, NULL_USEFUL_BUF_C); - /* external_aad */ - QCBOREncode_AddBytes(&cbor_encode_ctx, NULL_USEFUL_BUF_C); - /* fake payload */ - QCBOREncode_AddBytes(&cbor_encode_ctx, NULL_USEFUL_BUF_C); - QCBOREncode_CloseArray(&cbor_encode_ctx); - - /* get the result and convert it to struct useful_buf_c representation */ - qcbor_result = QCBOREncode_Finish(&cbor_encode_ctx, &tbs_first_part); - if(qcbor_result) { - /* Mainly means that the protected_headers were too big - (which should never happen) */ - return_value = T_COSE_ERR_SIG_STRUCT; - goto Done; - } - - /* Start the hashing */ - hash_alg_id = hash_alg_id_from_sig_alg_id(cose_alg_id); - /* Don't check hash_alg_id for failure. t_cose_crypto_hash_start() - will handle it properly - */ - return_value = t_cose_crypto_hash_start(&hash_ctx, hash_alg_id); - if(return_value) { - goto Done; - } - - /* Hash the first part of the TBS. Take all but the last two - * bytes. The last two bytes are the fake payload from above. It - * is replaced by the real payload which is hashed next. The fake - * payload is needed so the array count is right. This is one of - * the main things that make it possible to implement with one - * buffer for the whole cose sign1. - */ - t_cose_crypto_hash_update(&hash_ctx, - useful_buf_head(tbs_first_part, - tbs_first_part.len - 2)); - - /* Hash the payload */ - t_cose_crypto_hash_update(&hash_ctx, payload); - - /* Finish the hash and set up to return it */ - return_value = t_cose_crypto_hash_finish(&hash_ctx, - buffer_for_hash, - hash); - -Done: - return return_value; -} - - -/* - * Public function. See t_cose_util.h - */ -enum t_cose_err_t -get_short_circuit_kid(struct useful_buf buffer_for_kid, - struct useful_buf_c *kid) -{ - /* This is a random hard coded key ID that is used to indicate - * short-circuit signing. It is OK to hard code this as the - * probability of collision with this ID is very low and the same - * as for collision between any two key IDs of any sort. - */ - uint8_t defined_short_circuit_kid[] = { - 0xef, 0x95, 0x4b, 0x4b, 0xd9, 0xbd, 0xf6, 0x70, - 0xd0, 0x33, 0x60, 0x82, 0xf5, 0xef, 0x15, 0x2a, - 0xf8, 0xf3, 0x5b, 0x6a, 0x6c, 0x00, 0xef, 0xa6, - 0xa9, 0xa7, 0x1f, 0x49, 0x51, 0x7e, 0x18, 0xc6}; - - /* Prevent a dumb error where the size constant in the header is - * wrong.This check will be evaluated at compile time and optimize - * out when all is correct. - */ - if(sizeof(defined_short_circuit_kid) != T_COSE_SHORT_CIRCUIT_KID_SIZE) { - return T_COSE_ERR_BAD_SHORT_CIRCUIT_KID; - } - - *kid = useful_buf_copy(buffer_for_kid, - USEFUL_BUF_FROM_BYTE_ARRAY_LITERAL( - defined_short_circuit_kid)); - - return useful_buf_c_is_null(*kid) ? - T_COSE_ERR_KEY_BUFFER_SIZE : - T_COSE_SUCCESS; -} diff --git a/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/t_cose/src/t_cose_util.h b/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/t_cose/src/t_cose_util.h deleted file mode 100644 index 7b39dc3..0000000 --- a/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/t_cose/src/t_cose_util.h +++ /dev/null @@ -1,126 +0,0 @@ -/* - * t_cose_util.h - * - * Copyright 2019, Laurence Lundblade - * - * SPDX-License-Identifier: BSD-3-Clause - * - * See BSD-3-Clause license in README.mdE. - */ - - -#ifndef __T_COSE_UTIL_H__ -#define __T_COSE_UTIL_H__ - -#include -#include "useful_buf.h" -#include "t_cose_common.h" - -/** - * \file t_cose_util.h - * - * \brief Utility functions used internally by the t_cose implementation. - * - */ - - -/** - * \brief Return hash algorithm ID from a signature algorithm ID - * - * \param[in] cose_sig_alg_id A COSE signature algorithm identifier. - * - * \return \c INT32_MAX when the signature algorithm ID is not known. - * - * This works off of algorithm identifiers defined in the [IANA COSE - * Registry] (https://www.iana.org/assignments/cose/cose.xhtml). - * Corresponding local integer constants are defined in - * t_cose_defines.h. - * - * COSE signing algorithms are the combination of public key - * algorithm, curve, key size, hash algorithm and hash size. They are - * simple integers making them convenient for direct use in code. - * - * This function returns an identifier for only the hash algorithm - * from the combined identifier. - * - * If the needed algorithm identifiers are not in the IANA registry, - * they can be added to it. This will take some time and work. It is - * also fine to use algorithms in the proprietary space. - */ -int32_t hash_alg_id_from_sig_alg_id(int32_t cose_sig_alg_id); - - -/** - * \brief Create the hash of the to-be-signed (TBS) bytes for COSE. - * - * \param[in] cose_alg_id The COSE signing algorithm ID. Used to - * determine which hash function to use. - * \param[in] buffer_for_hash Pointer and length of buffer into which - * the resulting hash is put. - * \param[out] hash Pointer and length of the - * resulting hash. - * \param[in] protected_headers The CBOR encoded protected headers. - * \param[in] payload The CBOR encoded payload - * - * \return This returns one of the error codes defined by \ref t_cose_err_t. - * - * \retval T_COSE_ERR_SIG_STRUCT - * Most likely this is because the protected_headers passed in - * is larger than \ref T_COSE_SIGN1_MAX_PROT_HEADER. - * \retval T_COSE_ERR_UNSUPPORTED_HASH - * If the hash algorithm is not known. - * \retval T_COSE_ERR_HASH_GENERAL_FAIL - * In case of some general hash failure. - * - * The input to the public key signature algorithm in COSE is the hash - * of a CBOR encoded structure containing the protected headers - * algorithm ID and a few other things. This formats that structure - * and computes the hash of it. These are known as the to-be-signed or - * "TBS" bytes. - */ -enum t_cose_err_t create_tbs_hash(int32_t cose_alg_id, - struct useful_buf buffer_for_hash, - struct useful_buf_c *hash, - struct useful_buf_c protected_headers, - struct useful_buf_c payload); - - -/** - * Size of the key returned by get_short_circuit_kid(). It is always - * this size. - */ -#define T_COSE_SHORT_CIRCUIT_KID_SIZE 32 - - -/** - * \brief Get the special kid for short-circuit signing. - * - * \param[in] buffer_for_kid Pointer and length of buffer into which - * the resulting hash is put. It should - * always be at least \ref - * T_COSE_SHORT_CIRCUIT_KID_SIZE. - * \param[out] kid Pointer and length of the returned kid. - * - * \retval T_COSE_SUCCESS - * The kid was returned. - * \retval T_COSE_ERR_KEY_BUFFER_SIZE - * \c buffer_for_kid is too small - * - * This always returns the same key ID. It always indicates - * short-circuit signing. It is OK to hard code this as the - * probability of collision with this ID is extremely low and the same - * as for collision between any two key IDs (kids) of any sort. - * - * This is the value of the kid. - * - * 0xef, 0x95, 0x4b, 0x4b, 0xd9, 0xbd, 0xf6, 0x70, - * 0xd0, 0x33, 0x60, 0x82, 0xf5, 0xef, 0x15, 0x2a, - * 0xf8, 0xf3, 0x5b, 0x6a, 0x6c, 0x00, 0xef, 0xa6, - * 0xa9, 0xa7, 0x1f, 0x49, 0x51, 0x7e, 0x18, 0xc6 - * - */ -enum t_cose_err_t -get_short_circuit_kid(struct useful_buf buffer_for_kid, - struct useful_buf_c *kid); - -#endif /* __T_COSE_UTIL_H__ */ diff --git a/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/tfm_attest_hal.h b/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/tfm_attest_hal.h deleted file mode 100755 index b43b109..0000000 --- a/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/tfm_attest_hal.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (c) 2019, Arm Limited. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - * - */ - -#ifndef __TFM_ATTEST_HAL_H__ -#define __TFM_ATTEST_HAL_H__ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * \brief Security lifecycle of the device - */ -enum tfm_security_lifecycle_t { - TFM_SLC_UNKNOWN = 0x0000u, - TFM_SLC_ASSEMBLY_AND_TEST = 0x1000u, - TFM_SLC_PSA_ROT_PROVISIONING = 0x2000u, - TFM_SLC_SECURED = 0x3000u, - TFM_SLC_NON_PSA_ROT_DEBUG = 0x4000u, - TFM_SLC_RECOVERABLE_PSA_ROT_DEBUG = 0x5000u, - TFM_SLC_DECOMMISSIONED = 0x6000u, -}; - -/** - * \brief Retrieve the security lifecycle of the device - * - * Security lifecycle is a mandatory claim in the initial attestation token. - * - * \return According to \ref tfm_security_lifecycle_t - */ -enum tfm_security_lifecycle_t tfm_attest_hal_get_security_lifecycle(void); - -/** - * \brief Retrieve the verification service indicator for initial attestation. - * - * It is used by relying party to locate a validation service for the token. - * It can be a text string that can be used to locate the service or can be a - * URL specifying the address of the service. - * - * \param[out] size Length of the string, without the termination zero byte. - * - * \return NULL pointer if not available otherwise the address of the - * verification service string in the device memory. - */ -const char * -tfm_attest_hal_get_verification_service(uint32_t *size); - -/** - * \brief Retrieve the name of the profile definition document for initial - * attestation. - * - * This document describes the 'profile' of the initial attestation token, - * being a full description of the claims, their usage, verification and - * token signing. - * - * \param[out] size Length of the document name, without the termination zero - * byte. - * - * \return NULL pointer if not available otherwise the address of the document - * name string in the device memory. - */ -const char * -tfm_attest_hal_get_profile_definition(uint32_t *size); - -#ifdef __cplusplus -} -#endif - -#endif /* __TFM_ATTEST_HAL_H__ */ diff --git a/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/tfm_boot_status.h b/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/tfm_boot_status.h deleted file mode 100755 index dbcc6ce..0000000 --- a/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/tfm_boot_status.h +++ /dev/null @@ -1,207 +0,0 @@ -/* - * Copyright (c) 2018-2019, Arm Limited. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - * - */ - -#ifndef __TFM_BOOT_STATUS_H__ -#define __TFM_BOOT_STATUS_H__ - -#include -#include - - -#ifdef __cplusplus -extern "C" { -#endif - -/* Major numbers (4 bit) to identify - * the consumer of shared data in runtime SW - */ -#define TLV_MAJOR_CORE 0x0 -#define TLV_MAJOR_IAS 0x1 - -/** - * The shared data between boot loader and runtime SW is TLV encoded. The - * shared data is stored in a well known location in secure memory and this is - * a contract between boot loader and runtime SW. - * - * The structure of shared data must be the following: - * - At the beginning there must be a header: struct shared_data_tlv_header - * This contains a magic number and a size field which covers the entire - * size of the shared data area including this header. - * - After the header there come the entries which are composed from an entry - * header structure: struct shared_data_tlv_entry and the data. In the entry - * header is a type field (tly_type) which identify the consumer of the - * entry in the runtime SW and specify the subtype of that data item. There - * is a size field (tlv_len) which covers the size of the entry header and - * the data. After this structure comes the actual data. - * - Arbitrary number and size of data entry can be in the shared memory area. - * - * This table gives of overview about the tlv_type field in the entry header. - * The tlv_type always composed from a major and minor number. Major number - * identifies the addressee in runtime SW, who should process the data entry. - * Minor number used to encode more info about the data entry. The actual - * definition of minor number could change per major number. In case of boot - * status data, which is going to be processed by initial attestation service - * the minor number is split further to two part: sw_module and claim. The - * sw_module identifies the SW component in the system which the data item - * belongs to and the claim part identifies the exact type of the data. - * - * |---------------------------------------| - * | tlv_type (16) | - * |---------------------------------------| - * | tlv_major(4)| tlv_minor(12) | - * |---------------------------------------| - * | MAJOR_IAS | sw_module(6) | claim(6) | - * |---------------------------------------| - * | MAJOR_CORE | TBD | - * |---------------------------------------| - */ - -/* Initial attestation: SW components / SW modules - * This list is intended to be adjusted per device. It contains more SW - * components than currently available in TF-M project. It serves as an example, - * what kind of SW components might be available. - */ -#define SW_GENERAL 0x00 -#define SW_BL2 0x01 -#define SW_PROT 0x02 -#define SW_AROT 0x03 -#define SW_SPE 0x04 -#define SW_NSPE 0x05 -#define SW_S_NS 0x06 -#define SW_MAX 0x07 - -/* Initial attestation: Claim per SW components / SW modules */ -/* Bits: 0-2 */ -#define SW_VERSION 0x00 -#define SW_SIGNER_ID 0x01 -#define SW_EPOCH 0x02 -#define SW_TYPE 0x03 -/* Bits: 3-5 */ -#define SW_MEASURE_VALUE 0x08 -#define SW_MEASURE_TYPE 0x09 - -/* Initial attestation: General claim does not belong any particular SW - * component. But they might be part of the boot status. - */ -#define BOOT_SEED 0x00 -#define HW_VERSION 0x01 -#define SECURITY_LIFECYCLE 0x02 - -/* Minor numbers (12 bit) to identify attestation service related data */ -#define TLV_MINOR_IAS_BOOT_SEED ((SW_GENERAL << 6) | BOOT_SEED) -#define TLV_MINOR_IAS_HW_VERSION ((SW_GENERAL << 6) | HW_VERSION) -#define TLV_MINOR_IAS_SLC ((SW_GENERAL << 6) | SECURITY_LIFECYCLE) - -/* Bootloader - It can be more stage */ -#define TLV_MINOR_IAS_BL2_MEASURE_VALUE ((SW_BL2 << 6) | SW_MEASURE_VALUE) -#define TLV_MINOR_IAS_BL2_MEASURE_TYPE ((SW_BL2 << 6) | SW_MEASURE_TYPE) -#define TLV_MINOR_IAS_BL2_VERSION ((SW_BL2 << 6) | SW_VERSION) -#define TLV_MINOR_IAS_BL2_SIGNER_ID ((SW_BL2 << 6) | SW_SIGNER_ID) -#define TLV_MINOR_IAS_BL2_EPOCH ((SW_BL2 << 6) | SW_EPOCH) -#define TLV_MINOR_IAS_BL2_TYPE ((SW_BL2 << 6) | SW_TYPE) - -/* PROT: PSA Root of Trust */ -#define TLV_MINOR_IAS_PROT_MEASURE_VALUE ((SW_PROT << 6) | SW_MEASURE_VALUE) -#define TLV_MINOR_IAS_PROT_MEASURE_TYPE ((SW_PROT << 6) | SW_MEASURE_TYPE) -#define TLV_MINOR_IAS_PROT_VERSION ((SW_PROT << 6) | SW_VERSION) -#define TLV_MINOR_IAS_PROT_SIGNER_ID ((SW_PROT << 6) | SW_SIGNER_ID) -#define TLV_MINOR_IAS_PROT_EPOCH ((SW_PROT << 6) | SW_EPOCH) -#define TLV_MINOR_IAS_PROT_TYPE ((SW_PROT << 6) | SW_TYPE) - -/* AROT: Application Root of Trust */ -#define TLV_MINOR_IAS_AROT_MEASURE_VALUE ((SW_AROT << 6) | SW_MEASURE_VALUE) -#define TLV_MINOR_IAS_AROT_MEASURE_TYPE ((SW_AROT << 6) | SW_MEASURE_TYPE) -#define TLV_MINOR_IAS_AROT_VERSION ((SW_AROT << 6) | SW_VERSION) -#define TLV_MINOR_IAS_AROT_SIGNER_ID ((SW_AROT << 6) | SW_SIGNER_ID) -#define TLV_MINOR_IAS_AROT_EPOCH ((SW_AROT << 6) | SW_EPOCH) -#define TLV_MINOR_IAS_AROT_TYPE ((SW_AROT << 6) | SW_TYPE) - -/* Non-secure processing environment - single non-secure image */ -#define TLV_MINOR_IAS_NSPE_MEASURE_VALUE ((SW_NSPE << 6) | SW_MEASURE_VALUE) -#define TLV_MINOR_IAS_NSPE_MEASURE_TYPE ((SW_NSPE << 6) | SW_MEASURE_TYPE) -#define TLV_MINOR_IAS_NSPE_VERSION ((SW_NSPE << 6) | SW_VERSION) -#define TLV_MINOR_IAS_NSPE_SIGNER_ID ((SW_NSPE << 6) | SW_SIGNER_ID) -#define TLV_MINOR_IAS_NSPE_EPOCH ((SW_NSPE << 6) | SW_EPOCH) -#define TLV_MINOR_IAS_NSPE_TYPE ((SW_NSPE << 6) | SW_TYPE) - -/* Secure processing environment (ARoT + PRoT) - single secure image */ -#define TLV_MINOR_IAS_SPE_MEASURE_VALUE ((SW_SPE << 6) | SW_MEASURE_VALUE) -#define TLV_MINOR_IAS_SPE_MEASURE_TYPE ((SW_SPE << 6) | SW_MEASURE_TYPE) -#define TLV_MINOR_IAS_SPE_VERSION ((SW_SPE << 6) | SW_VERSION) -#define TLV_MINOR_IAS_SPE_SIGNER_ID ((SW_SPE << 6) | SW_SIGNER_ID) -#define TLV_MINOR_IAS_SPE_EPOCH ((SW_SPE << 6) | SW_EPOCH) -#define TLV_MINOR_IAS_SPE_TYPE ((SW_SPE << 6) | SW_TYPE) - -/* SPE + NSPE - combined secure and non-secure image */ -#define TLV_MINOR_IAS_S_NS_MEASURE_VALUE ((SW_S_NS << 6) | SW_MEASURE_VALUE) -#define TLV_MINOR_IAS_S_NS_MEASURE_TYPE ((SW_S_NS << 6) | SW_MEASURE_TYPE) -#define TLV_MINOR_IAS_S_NS_VERSION ((SW_S_NS << 6) | SW_VERSION) -#define TLV_MINOR_IAS_S_NS_SIGNER_ID ((SW_S_NS << 6) | SW_SIGNER_ID) -#define TLV_MINOR_IAS_S_NS_EPOCH ((SW_S_NS << 6) | SW_EPOCH) -#define TLV_MINOR_IAS_S_NS_TYPE ((SW_S_NS << 6) | SW_TYPE) - -/* General macros to handle TLV type */ -#define MAJOR_MASK 0xF /* 4 bit */ -#define MAJOR_POS 12 /* 12 bit */ -#define MINOR_MASK 0xFFF /* 12 bit */ - -#define SET_TLV_TYPE(major, minor) \ - ((((major) & MAJOR_MASK) << MAJOR_POS) | ((minor) & MINOR_MASK)) -#define GET_MAJOR(tlv_type) ((tlv_type) >> MAJOR_POS) -#define GET_MINOR(tlv_type) ((tlv_type) & MINOR_MASK) - -/* Initial attestation specific macros */ -#define MODULE_POS 6 /* 6 bit */ -#define CLAIM_MASK 0x3F /* 6 bit */ -#define MEASUREMENT_CLAIM_POS 3 /* 3 bit */ - -#define GET_IAS_MODULE(tlv_type) (GET_MINOR(tlv_type) >> MODULE_POS) -#define GET_IAS_CLAIM(tlv_type) (GET_MINOR(tlv_type) & CLAIM_MASK) -#define SET_IAS_MINOR(sw_module, claim) (((sw_module) << 6) | (claim)) - -#define GET_IAS_MEASUREMENT_CLAIM(ias_claim) ((ias_claim) >> \ - MEASUREMENT_CLAIM_POS) - -/* Magic value which marks the beginning of shared data area in memory */ -#define SHARED_DATA_TLV_INFO_MAGIC 0x2016 - -/** - * Shared data TLV header. All fields in little endian. - * - * ----------------------------------- - * | tlv_magic(16) | tlv_tot_len(16) | - * ----------------------------------- - */ -struct shared_data_tlv_header { - uint16_t tlv_magic; - uint16_t tlv_tot_len; /* size of whole TLV area (including this header) */ -}; - -#define SHARED_DATA_HEADER_SIZE sizeof(struct shared_data_tlv_header) - -/** - * Shared data TLV entry header format. All fields in little endian. - * - * ------------------------------- - * | tlv_type(16) | tlv_len(16) | - * ------------------------------- - * | Raw data | - * ------------------------------- - */ -struct shared_data_tlv_entry { - uint16_t tlv_type; - uint16_t tlv_len; /* size of single TLV entry (including this header). */ -}; - -#define SHARED_DATA_ENTRY_HEADER_SIZE sizeof(struct shared_data_tlv_entry) -#define SHARED_DATA_ENTRY_SIZE(size) (size + SHARED_DATA_ENTRY_HEADER_SIZE) - -#ifdef __cplusplus -} -#endif - -#endif /* __TFM_BOOT_STATUS_H__ */ diff --git a/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/tfm_plat_boot_seed.h b/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/tfm_plat_boot_seed.h deleted file mode 100755 index 11b79f0..0000000 --- a/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/tfm_plat_boot_seed.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2018, Arm Limited. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - * - */ - -#ifndef __TFM_PLAT_BOOT_SEED_H__ -#define __TFM_PLAT_BOOT_SEED_H__ -/** - * \file tfm_plat_boot_seed.h - * - * Boot seed is used by a validating entity to ensure multiple reports were - * generated in the same boot session. Boot seed is a random number, generated - * only once during a boot cycle and its value is constant in the same cycle. - * Size recommendation is 256-bit to meet the statistically improbable property. - * Boot seed can be generated by secure boot loader an included to the measured - * boot state or can be generated by PRoT SW. - */ - -/** - * \note The interfaces defined in this file must be implemented for each - * SoC. - */ - -#include -#include "tfm_plat_defs.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/*! - * \def BOOT_SEED_SIZE - * - * \brief Size of boot seed in bytes. - */ -#define BOOT_SEED_SIZE (32u) - -/** - * \brief Gets the boot seed, which is a constant random number during a boot - * cycle. - * - * \param[in] size The required size of boot seed in bytes - * \param[out] buf Pointer to the buffer to store boot seed - * - * \return TFM_PLAT_ERR_SUCCESS if the value is generated correctly. Otherwise, - * it returns TFM_PLAT_ERR_SYSTEM_ERR. - */ -enum tfm_plat_err_t tfm_plat_get_boot_seed(uint32_t size, uint8_t *buf); - -#ifdef __cplusplus -} -#endif - -#endif /* __TFM_PLAT_BOOT_SEED_H__ */ diff --git a/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/tfm_plat_crypto_keys.h b/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/tfm_plat_crypto_keys.h deleted file mode 100755 index 386d61f..0000000 --- a/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/tfm_plat_crypto_keys.h +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright (c) 2017-2019, Arm Limited. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - * - */ - -#ifndef __TFM_PLAT_CRYPTO_KEYS_H__ -#define __TFM_PLAT_CRYPTO_KEYS_H__ -/** - * \note The interfaces defined in this file must be implemented for each - * SoC. - */ - -#include -#include "tfm_plat_defs.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * Elliptic curve key type identifiers according to RFC8152 (COSE encoding) - * https://www.iana.org/assignments/cose/cose.xhtml#elliptic-curves - */ -enum ecc_curve_t { - P_256 = 1, /* NIST P-256 also known as secp256r1 */ - P_384 = 2, /* NIST P-384 also known as secp384r1 */ - P_521 = 3, /* NIST P-521 also known as secp521r1 */ - X25519 = 4, /* X25519 for use with ECDH only */ - X448 = 5, /* X448 for use with ECDH only */ - ED25519 = 6, /* Ed25519 for use with EdDSA only */ - ED448 = 7, /* Ed448 for use with EdDSA only */ -}; - -/** - * Structure definition to carry pointer and size information about an Elliptic - * curve key which is stored in a buffer(key_buf) in raw format (without - * encoding): - * - priv_key Base address of the private key in key_buf. It must be - * present on the device. - * - priv_key_size Size of the private key in bytes. - * - pubx_key Base address of x-coordinate of the public key in key_buf. - * It can be empty, because it can be recomputed based on - * private key. - * - pubx_key_size Length of x-coordinate of the public key in key_buf. - * It can be empty, because it can be recomputed based on - * private key. - * - puby_key Base address of y-coordinate of the public key in key_buf. - * It can be empty, because either it can be recomputed based - * on private key or some curve type works without it. - * - puby_key_size Length of y-coordinate of the public key in key_buf. - */ -struct ecc_key_t { - uint8_t *priv_key; - uint32_t priv_key_size; - uint8_t *pubx_key; - uint32_t pubx_key_size; - uint8_t *puby_key; - uint32_t puby_key_size; -}; - -#define ECC_P_256_KEY_SIZE (96u) /* 3 x 32 = 96 bytes priv + pub-x + pub-y */ - -/** - * \brief Gets hardware unique key for encryption - * - * \param[out] key Buf to store the key in - * \param[in] size Size of the buffer - * - * \return Returns error code specified in \ref tfm_plat_err_t - */ -enum tfm_plat_err_t tfm_plat_get_crypto_huk(uint8_t *key, uint32_t size); - -/** - * \brief Get the initial attestation key - * - * The device MUST contain an initial attestation key, which is used to sign the - * token. Initial attestation service supports elliptic curve signing - * algorithms. Device maker can decide whether store only the private key on the - * device or store both (public and private) key. Public key can be recomputed - * based on private key. Keys must be provided in raw format, just binary data - * without any encoding (DER, COSE). Caller provides a buffer to copy all the - * available key components to there. Key components must be copied after - * each other to the buffer. The base address and the length of each key - * component must be indicating in the corresponding field of ecc_key - * (\ref struct ecc_key_t). - * Curve_type indicates to which curve belongs the key. - * - * - * Keys must be provided in - * - * \param[in/out] key_buf Buffer to store the initial attestation key. - * \param[in] size Size of the buffer. - * \param[out] ecc_key A structure to carry pointer and size information - * about the initial attestation key, which is - * stored in key_buf. - * \param[out] curve_type The type of the EC curve, which the key belongs - * to according to \ref ecc_curve_t - * - * \return Returns error code specified in \ref tfm_plat_err_t - */ -enum tfm_plat_err_t -tfm_plat_get_initial_attest_key(uint8_t *key_buf, - uint32_t size, - struct ecc_key_t *ecc_key, - enum ecc_curve_t *curve_type); - -#ifdef __cplusplus -} -#endif - -#endif /* __TFM_PLAT_CRYPTO_KEYS_H__ */ diff --git a/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/tfm_plat_defs.h b/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/tfm_plat_defs.h deleted file mode 100755 index 66747ee..0000000 --- a/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/tfm_plat_defs.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2017-2018, Arm Limited. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - * - */ - -#ifndef __TFM_PLAT_DEFS_H__ -#define __TFM_PLAT_DEFS_H__ -/** - * \note The interfaces defined in this file must be implemented for each - * target. - */ - -#include -#include - -enum tfm_plat_err_t { - TFM_PLAT_ERR_SUCCESS = 0, - TFM_PLAT_ERR_SYSTEM_ERR, - TFM_PLAT_ERR_MAX_VALUE, - /* Following entry is only to ensure the error code of int size */ - TFM_PLAT_ERR_FORCE_INT_SIZE = INT_MAX -}; - -/*! - * \def TFM_LINK_SET_OBJECT_IN_PARTITION_SECTION(TFM_PARTITION_NAME) - * - * \brief This macro provides a mechanism to place a function code in a specific - * secure partition at linker time in TF-M Level 3. - * - * \param[in] TFM_PARTITION_NAME TF-M partition name assigned in the manifest - * file "tfm_partition_name" field. - */ -#define TFM_LINK_SET_OBJECT_IN_PARTITION_SECTION(TFM_PARTITION_NAME) \ - __attribute__((section(TFM_PARTITION_NAME"_ATTR_FN"))) - -#endif /* __TFM_PLAT_DEFS_H__ */ diff --git a/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/tfm_plat_device_id.h b/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/tfm_plat_device_id.h deleted file mode 100755 index dcce837..0000000 --- a/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_impl/tfm_plat_device_id.h +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (c) 2018-2019, Arm Limited. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - * - */ - -#ifndef __TFM_PLAT_DEVICE_ID_H__ -#define __TFM_PLAT_DEVICE_ID_H__ -/** - * \file tfm_plat_device_id.h - * - * The interfaces defined in this file are meant to provide the following - * attributes of the device: - * - Instance ID: Unique identifier of the device. - * - Implementation ID: Original implementation signer of the attestation key. - * - Hardware version: Identify the GDSII that went to fabrication. - */ - -/** - * \note The interfaces defined in this file must be implemented for each - * SoC. - */ - -#include -#include "tfm_plat_defs.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * \def INSTANCE_ID_MAX_SIZE - * - * \brief Maximum size of instance ID in bytes - */ -#define INSTANCE_ID_MAX_SIZE (33u) - -/** - * \def IMPLEMENTATION_ID_MAX_SIZE - * - * \brief Maximum size of implementation ID in bytes - */ -#define IMPLEMENTATION_ID_MAX_SIZE (32u) - -/** - * \def HW_VERSION_MAX_SIZE - * - * \brief Maximum size of hardware version in bytes - * - * Recommended to use the European Article Number format: EAN-13+5 - */ -#define HW_VERSION_MAX_SIZE (18u) - -/** - * \brief Get the UEID of the device. - * - * This mandatory claim represents the unique identifier of the instance. - * In the PSA definition is a hash of the public attestation key of the - * instance. The claim will be represented by the EAT standard claim UEID - * of type GUID. The EAT definition of a GUID type is that it will be between - * 128 & 256 bits but this implementation will use the full 256 bits to - * accommodate a hash result. - * - * \param[in/out] size As an input value it indicates the size of the caller - * allocated buffer (in bytes) to store the UEID. At return - * its value is updated with the exact size of the UEID. - * \param[out] buf Pointer to the buffer to store the UEID - * - * \return Returns error code specified in \ref tfm_plat_err_t - */ -enum tfm_plat_err_t tfm_plat_get_instance_id(uint32_t *size, uint8_t *buf); - -/** - * \brief Get the Implementation ID of the device. - * - * This mandatory claim represents the original implementation signer of the - * attestation key and identifies the contract between the report and - * verification. A verification service will use this claim to locate the - * details of the verification process. The claim will be represented by a - * custom EAT claim with a value consisting of a CBOR byte string. The size of - * this string will normally be 32 bytes to accommodate a 256 bit hash. - * - * \param[in/out] size As an input value it indicates the size of the caller - * allocated buffer (in bytes) to store the implementation - * ID. At return its value is updated with the exact size - * of the implementation ID. - * \param[out] buf Pointer to the buffer to store the implementation ID - * - * \return Returns error code specified in \ref tfm_plat_err_t - */ -enum tfm_plat_err_t tfm_plat_get_implementation_id(uint32_t *size, - uint8_t *buf); - -/** - * \brief Get the hardware version of the device. - * - * This optional claim provides metadata linking the token to the GDSII that - * went to fabrication for this instance. It is represented as CBOR text string. - * It is recommended to use for identification the format of the European - * Article Number: EAN-13+5. - * - * \param[in/out] size As an input value it indicates the size of the caller - * allocated buffer (in bytes) to store the HW version. At - * return its value is updated with the exact size of the - * HW version. - * \param[out] buf Pointer to the buffer to store the HW version - * - * \return Returns error code specified in \ref tfm_plat_err_t - */ -enum tfm_plat_err_t tfm_plat_get_hw_version(uint32_t *size, uint8_t *buf); - -#ifdef __cplusplus -} -#endif - -#endif /* __TFM_PLAT_DEVICE_ID_H__ */ diff --git a/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_memory_utils.h b/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_memory_utils.h deleted file mode 100644 index 852399e..0000000 --- a/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IMPL/tfm_memory_utils.h +++ /dev/null @@ -1,39 +0,0 @@ -/* -* Copyright (c) 2018-2019 ARM Limited. All rights reserved. -* -* SPDX-License-Identifier: Apache-2.0 -* -* Licensed under the Apache License, Version 2.0 (the License); you may -* not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an AS IS BASIS, WITHOUT -* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#ifndef __TFM_MEMORY_UTILS_H__ -#define __TFM_MEMORY_UTILS_H__ - -#include -#include - -#ifdef __cplusplus -extern "C" -{ -#endif - -void *tfm_memcpy(void *dest, const void *src, size_t num) -{ - return (memcpy(dest, src, num)); -} - -#ifdef __cplusplus -} -#endif - -#endif /* __TFM_MEMORY_UTILS_H__ */ diff --git a/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IPC/psa_attest_inject_key.c b/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IPC/psa_attest_inject_key.c deleted file mode 100755 index 239b8d3..0000000 --- a/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IPC/psa_attest_inject_key.c +++ /dev/null @@ -1,55 +0,0 @@ -/* -* Copyright (c) 2018-2019 ARM Limited. All rights reserved. -* -* SPDX-License-Identifier: Apache-2.0 -* -* Licensed under the Apache License, Version 2.0 (the License); you may -* not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an AS IS BASIS, WITHOUT -* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#include "psa_attest_inject_key.h" -#include "psa/crypto.h" -#include "psa/client.h" -#include "psa_manifest/sid.h" - -#define MINOR_VER 1 - -psa_status_t -psa_attestation_inject_key(const uint8_t *key_data, - size_t key_data_length, - psa_key_type_t type, - uint8_t *public_key_data, - size_t public_key_data_size, - size_t *public_key_data_length) -{ - psa_handle_t handle = PSA_NULL_HANDLE; - psa_status_t call_error = PSA_SUCCESS; - psa_invec in_vec[2] = { - { &type, sizeof(type) }, - { key_data, key_data_length } - }; - - psa_outvec out_vec[2] = { - { public_key_data, public_key_data_size }, - { public_key_data_length, sizeof(*public_key_data_length) } - }; - - handle = psa_connect(PSA_ATTEST_INJECT_KEY_ID, MINOR_VER); - if (handle <= 0) { - return (PSA_ERROR_COMMUNICATION_FAILURE); - } - - call_error = psa_call(handle, in_vec, 2, out_vec, 2); - - psa_close(handle); - return call_error; -} diff --git a/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IPC/psa_initial_attestation_api.c b/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IPC/psa_initial_attestation_api.c deleted file mode 100755 index ff90cc8..0000000 --- a/components/TARGET_PSA/services/attestation/COMPONENT_PSA_SRV_IPC/psa_initial_attestation_api.c +++ /dev/null @@ -1,79 +0,0 @@ -/* -* Copyright (c) 2018-2019 ARM Limited. All rights reserved. -* -* SPDX-License-Identifier: Apache-2.0 -* -* Licensed under the Apache License, Version 2.0 (the License); you may -* not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an AS IS BASIS, WITHOUT -* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#include "psa_initial_attestation_api.h" -#include "psa/crypto.h" -#include "psa/client.h" -#include "attestation.h" -#include -#include "psa_manifest/sid.h" - -#define MINOR_VER 1 - -enum psa_attest_err_t -psa_initial_attest_get_token(const uint8_t *challenge_obj, - uint32_t challenge_size, - uint8_t *token, - uint32_t *token_size) { - psa_status_t err_call; - psa_handle_t handle = PSA_NULL_HANDLE; - - psa_invec in_vec[1] = { { challenge_obj, challenge_size } }; - psa_outvec out_vec[1] = { { token, *token_size } }; - - handle = psa_connect(PSA_ATTEST_GET_TOKEN_ID, MINOR_VER); - if (handle <= 0) - { - return (PSA_ATTEST_ERR_GENERAL); - } - - err_call = psa_call(handle, in_vec, 1, out_vec, 1); - psa_close(handle); - - if (err_call < 0) - { - err_call = PSA_ATTEST_ERR_GENERAL; - } - - return ((enum psa_attest_err_t) err_call); -} - -enum psa_attest_err_t -psa_initial_attest_get_token_size(uint32_t challenge_size, - uint32_t *token_size) { - psa_status_t err_call; - psa_handle_t handle = PSA_NULL_HANDLE; - psa_invec in_vec[1] = { { &challenge_size, sizeof(uint32_t) } }; - psa_outvec out_vec[1] = { { token_size, sizeof(uint32_t) } }; - - handle = psa_connect(PSA_ATTEST_GET_TOKEN_SIZE_ID, MINOR_VER); - if (handle <= 0) - { - return (PSA_ATTEST_ERR_GENERAL); - } - - err_call = psa_call(handle, in_vec, 1, out_vec, 1); - psa_close(handle); - - if (err_call < 0) - { - err_call = PSA_ATTEST_ERR_GENERAL; - } - - return ((enum psa_attest_err_t) err_call); -} diff --git a/components/TARGET_PSA/services/attestation/LICENSE b/components/TARGET_PSA/services/attestation/LICENSE deleted file mode 100644 index 96810fd..0000000 --- a/components/TARGET_PSA/services/attestation/LICENSE +++ /dev/null @@ -1,2 +0,0 @@ -Unless specifically indicated otherwise in a file, TF-M files in this directory are licensed under the BSD-3-Clause license, -as can be found in: LICENSE-bsd-3-clause.txt diff --git a/components/TARGET_PSA/services/attestation/LICENSE-BSD-3-Clause b/components/TARGET_PSA/services/attestation/LICENSE-BSD-3-Clause deleted file mode 100644 index 476769c..0000000 --- a/components/TARGET_PSA/services/attestation/LICENSE-BSD-3-Clause +++ /dev/null @@ -1,26 +0,0 @@ -Copyright 2019 Arm Limited and affiliates. -SPDX-License-Identifier: BSD-3-Clause - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. -3. Neither the name of the copyright holder nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE -LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. diff --git a/components/TARGET_PSA/services/attestation/attestation.h b/components/TARGET_PSA/services/attestation/attestation.h deleted file mode 100755 index b2b8d1b..0000000 --- a/components/TARGET_PSA/services/attestation/attestation.h +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright (c) 2018-2019, Arm Limited. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - * - */ - -/** @addtogroup PSA-Attestation - * @{ - */ - - -#ifndef __ATTESTATION_H__ -#define __ATTESTATION_H__ - -#include "psa_initial_attestation_api.h" -#include "tfm_client.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * \brief Type of memory access - */ -enum attest_memory_access_t { - TFM_ATTEST_ACCESS_RO = 1, - TFM_ATTEST_ACCESS_RW = 2, -}; - -/** - * \brief Copy the boot data (coming from boot loader) from shared memory area - * to service memory area - * - * \param[in] major_type Major type of TLV entries to copy - * \param[out] ptr Pointer to the buffer to store the boot data - * \parma[in] len Size of the buffer to store the boot data - * - * \return Returns error code as specified in \ref psa_attest_err_t - */ -enum psa_attest_err_t -attest_get_boot_data(uint8_t major_type, void *ptr, uint32_t len); - -/** - * \brief Get the ID of the caller thread. - * - * \param[out] caller_id Pointer where to store caller ID - * - * \return Returns error code as specified in \ref psa_attest_err_t - */ -enum psa_attest_err_t -attest_get_caller_client_id(int32_t *caller_id); - -/** - * \brief Verify memory access rights - * - * \param[in] addr Pointer to the base of the address range to check - * \param[in] size Size of the address range to check - * \param[in] access Type of memory access as specified in - * \ref attest_memory_access - * - * \return Returns error code as specified in \ref psa_attest_err_t - */ -enum psa_attest_err_t -attest_check_memory_access(void *addr, - uint32_t size, - enum attest_memory_access_t access); - -/** - * \brief Initialise the initial attestation service during the TF-M boot up - * process. - * - * \return Returns PSA_ATTEST_ERR_SUCCESS if init has been completed, - * otherwise error as specified in \ref psa_attest_err_t - */ -enum psa_attest_err_t attest_init(void); - -/** - * \brief Get initial attestation token - * - * \param[in] in_vec Pointer to in_vec array, which contains input data - * to attestation service - * \param[in] num_invec Number of elements in in_vec array - * \param[in/out] out_vec Pointer out_vec array, which contains output data - * to attestation service - * \param[in] num_outvec Number of elements in out_vec array - * - * \return Returns error code as specified in \ref psa_attest_err_t - */ -enum psa_attest_err_t -initial_attest_get_token(const psa_invec *in_vec, uint32_t num_invec, - psa_outvec *out_vec, uint32_t num_outvec); - -/** - * \brief Get the size of the initial attestation token - * - * \param[in] in_vec Pointer to in_vec array, which contains input data - * to attestation service - * \param[in] num_invec Number of elements in in_vec array - * \param[out] out_vec Pointer to out_vec array, which contains pointer - * where to store the output data - * \param[in] num_outvec Number of elements in out_vec array - * - * \return Returns error code as specified in \ref psa_attest_err_t - */ -enum psa_attest_err_t -initial_attest_get_token_size(const psa_invec *in_vec, uint32_t num_invec, - psa_outvec *out_vec, uint32_t num_outvec); -#ifdef __cplusplus -} -#endif - -/** @}*/ // PSA-Attestation - -#endif /* __ATTESTATION_H__ */ diff --git a/components/TARGET_PSA/services/attestation/psa_attest_inject_key.h b/components/TARGET_PSA/services/attestation/psa_attest_inject_key.h deleted file mode 100644 index 3e934d3..0000000 --- a/components/TARGET_PSA/services/attestation/psa_attest_inject_key.h +++ /dev/null @@ -1,87 +0,0 @@ -/* -* Copyright (c) 2018-2019 ARM Limited. All rights reserved. -* -* SPDX-License-Identifier: Apache-2.0 -* -* Licensed under the Apache License, Version 2.0 (the License); you may -* not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an AS IS BASIS, WITHOUT -* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -/** @addtogroup PSA-Attestation - * @{ - */ - -#ifndef __PSA_INJECT_KEY_H__ -#define __PSA_INJECT_KEY_H__ - -#include "psa/crypto.h" -#include -#include - -#ifdef __cplusplus -extern "C" -{ -#endif - -/** - * \brief Generate or import a given key pair and export the public part in a binary format. - * Initial attestation key: Private key for ECDSA-P256 to sign initial attestation token. - * Attestation private key is a persistent key that saved to - * persistent storage with persistent storage id = 17. - * - * \param[in] key_data Buffer containing the private key data if given. - * It must conain the format described in the documentation - * of psa_export_public_key() for - * the chosen type. - * In case of generate the private key - NULL will pass. - * \param key_data_length Size of the \p data buffer in bytes - must be 256 bits. in case key_data isn't NULL. - * In case of private key generation - 0 will pass. - * \param type Key type - must be a ECC key type - * (a \c PSA_KEY_TYPE_ECC_KEYPAIR(PSA_ECC_CURVE_XXX) value). - * \param[out] data Buffer where the key data is to be written. - * \param data_size Size of the \p data buffer in bytes - - * needs to be bigger then the max size of the public part. - * \param[out] data_length On success, the number of bytes - * that make up the key data. - * - * \retval #PSA_SUCCESS - * Success. - * \retval #PSA_ERROR_INVALID_HANDLE - * \retval #PSA_ERROR_OCCUPIED_SLOT - * There is already a key in the specified slot. - * \retval #PSA_ERROR_NOT_SUPPORTED - * \retval #PSA_ERROR_INVALID_ARGUMENT - * \retval #PSA_ERROR_INSUFFICIENT_MEMORY - * \retval #PSA_ERROR_INSUFFICIENT_ENTROPY - * \retval #PSA_ERROR_COMMUNICATION_FAILURE - * \retval #PSA_ERROR_HARDWARE_FAILURE - * \retval #PSA_ERROR_TAMPERING_DETECTED - * \retval #PSA_ERROR_BAD_STATE - * The library has not been previously initialized by psa_crypto_init(). - * It is implementation-dependent whether a failure to initialize - * results in this error code. - */ -psa_status_t -psa_attestation_inject_key(const uint8_t *key_data, - size_t key_data_length, - psa_key_type_t type, - uint8_t *public_key_data, - size_t public_key_data_size, - size_t *public_key_data_length); - -#ifdef __cplusplus -} -#endif - -/** @}*/ // PSA-Attestation - -#endif /* __PSA_INJECT_KEY_H__ */ diff --git a/components/TARGET_PSA/services/attestation/psa_initial_attestation_api.h b/components/TARGET_PSA/services/attestation/psa_initial_attestation_api.h deleted file mode 100644 index 0b56499..0000000 --- a/components/TARGET_PSA/services/attestation/psa_initial_attestation_api.h +++ /dev/null @@ -1,233 +0,0 @@ -/* - * Copyright (c) 2018-2019, Arm Limited. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - * - */ - -/***************************************************************************/ -/* DRAFT UNDER REVIEW */ -/* These APIs are still evolving and are meant as a prototype for review.*/ -/* The APIs will change depending on feedback and will be firmed up */ -/* to a stable set of APIs once all the feedback has been considered. */ -/***************************************************************************/ - -/** @addtogroup PSA-Attestation - * @{ - */ - - -#ifndef __PSA_INITIAL_ATTESTATION_API_H__ -#define __PSA_INITIAL_ATTESTATION_API_H__ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * \brief PSA INITIAL ATTESTATION API version - */ -#define PSA_INITIAL_ATTEST_API_VERSION_MAJOR (0) -#define PSA_INITIAL_ATTEST_API_VERSION_MINOR (9) - -/** - * \enum psa_attest_err_t - * - * \brief Initial attestation service error types - * - */ -enum psa_attest_err_t { - /** Action was performed successfully */ - PSA_ATTEST_ERR_SUCCESS = 0, - /** Boot status data is unavailable or malformed */ - PSA_ATTEST_ERR_INIT_FAILED, - /** Token buffer is too small to store the created token there */ - PSA_ATTEST_ERR_TOKEN_BUFFER_OVERFLOW, - /** Some of the mandatory claims are unavailable*/ - PSA_ATTEST_ERR_CLAIM_UNAVAILABLE, - /** Some parameter or combination of parameters are recognised as invalid: - * - challenge size is not allowed - * - challenge object is unavailable - * - token buffer is unavailable - */ - PSA_ATTEST_ERR_INVALID_INPUT, - /** Unexpected error happened during operation */ - PSA_ATTEST_ERR_GENERAL, - /** Following entry is only to ensure the error code of integer size */ - PSA_ATTEST_ERR_FORCE_INT_SIZE = INT_MAX -}; - -/** - * The allowed size of input challenge in bytes: 32, 48, 64 - * Challenge can be a nonce from server - * or the hash of some combined data : nonce + attested data by caller. - */ -#define PSA_INITIAL_ATTEST_CHALLENGE_SIZE_32 (32u) -#define PSA_INITIAL_ATTEST_CHALLENGE_SIZE_48 (48u) -#define PSA_INITIAL_ATTEST_CHALLENGE_SIZE_64 (64u) - -/** - * The list of fixed claims in the initial attestation token is still evolving, - * you can expect slight changes in the future. - * - * The initial attestation token is planned to be aligned with future version of - * Entity Attestation Token format: - * https://tools.ietf.org/html/draft-mandyam-eat-01 - * - * Current list of claims: - * - Challenge: Input object from caller. Can be a single nonce from server - * or hash of nonce and attested data. It is intended to provide - * freshness to reports and the caller has responsibility to - * arrange this. Allowed length: 32, 48, 64 bytes. The claim is - * modeled to be eventually represented by the EAT standard - * claim nonce. Until such a time as that standard exists, - * the claim will be represented by a custom claim. Value - * is encoded as byte string. - * - * - Instance ID: It represents the unique identifier of the instance. In the - * PSA definition it is a hash of the public attestation key - * of the instance. The claim is modeled to be eventually - * represented by the EAT standard claim UEID of type GUID. - * Until such a time as that standard exists, the claim will be - * represented by a custom claim Value is encoded as byte - * string. - * - * - Verification service indicator: Optional, recommended claim. It is used by - * a Relying Party to locate a validation service for the token. - * The value is a text string that can be used to locate the - * service or a URL specifying the address of the service. The - * claim is modeled to be eventually represented by the EAT - * standard claim origination. Until such a time as that - * standard exists, the claim will be represented by a custom - * claim. Value is encoded as text string. - * - * - Profile definition: Optional, recommended claim. It contains the name of - * a document that describes the 'profile' of the token, being - * a full description of the claims, their usage, verification - * and token signing. The document name may include versioning. - * Custom claim with a value encoded as text string. - * - * - Implementation ID: It represents the original implementation signer of the - * attestation key and identifies the contract between the - * report and verification. A verification service will use this - * claim to locate the details of the verification process. - * Custom claim with a value encoded as byte string. - * - * - Security lifecycle: It represents the current lifecycle state of the - * instance. Custom claim with a value encoded as integer that - * is divided to convey a major state and a minor state. The - * PSA state and implementation state are encoded as follows: - * - version[15:8] - PSA lifecycle state - major - * - version[7:0] - IMPLEMENTATION DEFINED state - minor - * Possible PSA lifecycle states: - * - Unknown (0x1000u), - * - PSA_RoT_Provisioning (0x2000u), - * - Secured (0x3000u), - * - Non_PSA_RoT_Debug(0x4000u), - * - Recoverable_PSA_RoT_Debug (0x5000u), - * - Decommissioned (0x6000u) - * - * - Client ID: The partition ID of that secure partition or non-secure - * thread who called the initial attestation API. Custom claim - * with a value encoded as a *signed* integer. Negative number - * represents non-secure caller, positive numbers represents - * secure callers, zero is invalid. - * - * - HW version: Optional claim. Globally unique number in EAN-13 format - * identifying the GDSII that went to fabrication, HW and ROM. - * It can be used to reference the security level of the PSA-ROT - * via a certification website. Custom claim with a value is - * encoded as text string. - - * - Boot seed: It represents a random value created at system boot time that - * will allow differentiation of reports from different system - * sessions. The size is 32 bytes. Custom claim with a value is - * encoded as byte string. - * - * - Software components: Recommended claim. It represents the software state - * of the system. The value of the claim is an array of CBOR map - * entries, with one entry per software component within the - * device. Each map contains multiple claims that describe - * evidence about the details of the software component. - * - * - Measurement type: Optional claim. It represents the role of the - * software component. Value is encoded as short(!) text - * string. - * - * - Measurement value: It represents a hash of the invariant software - * component in memory at start-up time. The value must be a - * cryptographic hash of 256 bits or stronger.Value is - * encoded as byte string. - * - * - Security epoch: Optional claim. It represents the security control - * point of the software component. Value is encoded as - * unsigned integer. - * - * - Version: Optional claim. It represents the issued software version. - * Value is encoded as text string. - * - * - Signer ID: It represents the hash of a signing authority public key. - * Value is encoded as byte string. - * - * - Measurement description: Optional claim. It represents the way in which - * the measurement value of the software component is - * computed. Value is encoded as text string containing an - * abbreviated description (name) of the measurement method. - * - * - No software measurements: In the event that the implementation does not - * contain any software measurements then the software - * components claim above can be omitted but instead - * it is mandatory to include this claim to indicate this is a - * deliberate state. Custom claim a value is encoded as unsigned - * integer set to 1. - */ - -/** - * \brief Get initial attestation token - * - * \param[in] challenge_obj Pointer to buffer where challenge input is - * stored. Nonce and / or hash of attested data. - * Must be always - * \ref PSA_INITIAL_ATTEST_CHALLENGE_SIZE bytes - * long. - * \param[in] challenge_size Size of challenge object in bytes. - * \param[out] token Pointer to the buffer where attestation token - * must be stored. - * \param[in/out] token_size Size of allocated buffer for token, which - * updated by initial attestation service with - * final token size. - * - * \return Returns error code as specified in \ref psa_attest_err_t - */ -enum psa_attest_err_t -psa_initial_attest_get_token(const uint8_t *challenge_obj, - uint32_t challenge_size, - uint8_t *token, - uint32_t *token_size); - -/** - * \brief Get the exact size of initial attestation token in bytes. - * - * It just returns with the size of the IAT token. It can be used if the caller - * dynamically allocates memory for the token buffer. - * - * \param[in] challenge_size Size of challenge object in bytes. - * \param[out] token_size Size of the token in bytes, which is created by - * initial attestation service. - * - * \return Returns error code as specified in \ref psa_attest_err_t - */ -enum psa_attest_err_t -psa_initial_attest_get_token_size(uint32_t challenge_size, - uint32_t *token_size); - -#ifdef __cplusplus -} -#endif - -/** @}*/ // PSA-Attestation - -#endif /* __PSA_INITIAL_ATTESTATION_API_H__ */ diff --git a/components/TARGET_PSA/services/attestation/qcbor/.mbedignore b/components/TARGET_PSA/services/attestation/qcbor/.mbedignore deleted file mode 100644 index ab1cfb4..0000000 --- a/components/TARGET_PSA/services/attestation/qcbor/.mbedignore +++ /dev/null @@ -1 +0,0 @@ -test/* diff --git a/components/TARGET_PSA/services/attestation/qcbor/CMakeLists.txt b/components/TARGET_PSA/services/attestation/qcbor/CMakeLists.txt deleted file mode 100644 index 060462a..0000000 --- a/components/TARGET_PSA/services/attestation/qcbor/CMakeLists.txt +++ /dev/null @@ -1,41 +0,0 @@ -#------------------------------------------------------------------------------- -# Copyright (c) 2019, Arm Limited. All rights reserved. -# -# SPDX-License-Identifier: BSD-3-Clause -# -#------------------------------------------------------------------------------- - -cmake_minimum_required(VERSION 3.7) - -#Tell cmake where our modules can be found -list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/../../../cmake) - -#Include common stuff to control cmake. -include("Common/BuildSys") - -#Start an embedded project. -embedded_project_start(CONFIG "${CMAKE_CURRENT_LIST_DIR}/../../../ConfigDefault.cmake") -project(tfm_qcbor LANGUAGES C) -embedded_project_fixup() - -#Some project global settings -set (QCBOR_DIR "${CMAKE_CURRENT_LIST_DIR}") - -#Append all our source files to global lists. -list(APPEND ALL_SRC_C - "${QCBOR_DIR}/src/ieee754.c" - "${QCBOR_DIR}/src/qcbor_decode.c" - "${QCBOR_DIR}/src/qcbor_encode.c" - "${QCBOR_DIR}/src/UsefulBuf.c" - ) - -#Setting include directories -embedded_include_directories(PATH ${QCBOR_DIR}/inc ABSOLUTE) - -#Specify what we build (for the QCBOR, build as an object library) -add_library(${PROJECT_NAME} OBJECT ${ALL_SRC_C}) - -#Set common compiler flags -config_setting_shared_compiler_flags(${PROJECT_NAME}) - -embedded_project_end(${PROJECT_NAME}) diff --git a/components/TARGET_PSA/services/attestation/qcbor/README.md b/components/TARGET_PSA/services/attestation/qcbor/README.md deleted file mode 100644 index 58a7080..0000000 --- a/components/TARGET_PSA/services/attestation/qcbor/README.md +++ /dev/null @@ -1,175 +0,0 @@ -# QCBOR - -QCBOR encodes and decodes [RFC 7049](https://tools.ietf.org/html/rfc7049) CBOR. - -## Characteristics - -**Implemented in C with minimal dependency** – Only dependencies are - C99, , , and making it - highly portable. There are no #ifdefs to be configured at all. - -**Focused on C / native data representation** – Simpler code because - there is no support for encoding/decoding to/from JSON, pretty - printing, diagnostic notation... Only encoding from native C - representations and decoding to native C representations is supported. - -**Small simple memory model** – Malloc is not needed. The encode - context is 136 bytes, decode context is 104 bytes and the - description of decoded data item is 56 bytes. Stack use is light and - there is no recursion. The caller supplies the memory to hold the - encoded CBOR and encode/decode contexts so caller has full control - of memory usage making it good for embedded implementations that - have to run in small fixed memory. - -**Supports nearly all of RFC 7049** – Only minor, corner-case parts of - RFC 7049 are not directly supported (canonicalization, decimal - fractions, big floats). Decoding indefinite length strings is supported, - but requires a string allocator (see documentation). Encoding indefinite - length strings is not supported, but is also not necessary or - preferred. - -**Extensible and general** – Provides a way to handle data types that - are not directly supported. - -**Secure coding style** – Uses a construct called UsefulBuf as a - discipline for very safe coding the handling of binary data. - -**Small code size** – When optimized for size using the compiler -Os - option, x86 code is about 4KB (~1.1KB encode, ~2.5KB decode, - ~0.4KB common). Other decoders may be smaller, but they may - also do less for you, so overall size of the implementation may - be larger. For example, QCBOR internally tracks error status - so you don't have to check a return code on every operation. - -**Clear documented public interface** – The public interface is - separated from the implementation. It can be put to use without - reading the source. - -**Comprehensive test suite** – Easy to verify on a new platform - or OS with the test suite. The test suite dependencies are also - minimal, only additionally requiring for floating point - tests. - -## Code Status - -QCBOR was originally developed by Qualcomm. It was [open sourced -through CAF](https://source.codeaurora.org/quic/QCBOR/QCBOR/) with a -permissive Linux license, September 2018 (thanks Qualcomm!). - -This code in [Laurence's -GitHub](https://github.com/laurencelundblade/QCBOR) has diverged from -the CAF source with some small simplifications and tidying up. - -From Nov 3, 2018, the interface and code are fairly stable. Large -changes are not planned or expected, particularly in the -interface. The test coverage is pretty good. - -## Building - -There is a simple makefile for the UNIX style command line binary that -compiles everything to run the tests. - -These seven files, the contents of the src and inc directories, make -up the entire implementation. - -* inc - * UsefulBuf.h - * qcbor.h -* src - * UsefulBuf.c - * qcbor_encode.c - * qcbor_decode.c - * ieee754.h - * ieee754.c - -For most use cases you should just be able to add them to your -project. Hopefully the easy portability of this implementation makes -this work straight away, whatever your development environment is. - -The files ieee754.c and ieee754.h are support for half-precision -floating point. The encoding side of the floating point functionality -is about 500 bytes. If it is never called because no floating point -numbers are ever encoded, all 500 bytes will be dead stripped and not -impact code size. The decoding side is about 150 bytes of object -code. It is never dead stripped because it directly referenced by the -core decoder, however it doesn't add very much to the size. - -The test directory includes some tests that are nearly as portable as -the main implementation. If your development environment doesn't -support UNIX style command line and make, you should be able to make a -simple project and add the test files to it. Then just call -RunTests() to invoke them all. - - -## Changes from CAF Version -* Float support is restored -* Minimal length float encoding is added -* indefinite length arrays/maps are supported -* indefinite length strings are supported -* Tag decoding is changed; unlimited number of tags supported, any tag -value supported, tag utility function for easier tag checking -* Addition functions in UsefulBuf -* QCBOREncode_Init takes a UsefulBuf instead of a pointer and size -* QCBOREncode_Finish takes a UsefulBufC and EncodedCBOR is remove -* bstr wrapping of arrays/maps is replaced with OpenBstrwrap -* AddRaw renamed to AddEncoded and can now only add whole arrays or maps, -not partial maps and arrays (simplification; was a dangerous feature) -* Finish cannot be called repeatedly on a partial decode (some tests used -this, but it is not really a good thing to use in the first place) -* UsefulOutBuf_OutUBuf changed to work differently -* UsefulOutBuf_Init works differently -* The "_3" functions are replaced with a small number of simpler functions -* There is a new AddTag functon instead of the "_3" functions, making -the interface simpler and saving some code -* QCBOREncode_AddRawSimple_2 is removed (the macros that referenced -still exist and work the same) - -## Credits -* Ganesh Kanike for porting to QSEE -* Mark Bapst for sponsorship and release as open source by Qualcomm -* Sachin Sharma for release through CAF -* Tamas Ban for porting to TF-M and 32-bit ARM - -## Copyright and License - -QCBOR is available under what is essentially the 3-Clause BSD License. - -Files created inside Qualcomm and open-sourced through CAF (The Code -Aurora Forum) have a slightly modified 3-Clause BSD License. The -modification additionally disclaims NON-INFRINGEMENT. - -Files created after release to CAF use the standard 3-Clause BSD -License with no modification. These files have the SPDX license -identifier, "SPDX-License-Identifier: BSD-3-Clause" in them. - -### BSD-3-Clause license - -* Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright -notice, this list of conditions and the following disclaimer in the -documentation and/or other materials provided with the distribution. - -* Neither the name of the copyright holder nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -### Copyright for this README - -Copyright (c) 2018-2019, Laurence Lundblade. All rights reserved. - - - diff --git a/components/TARGET_PSA/services/attestation/qcbor/inc/UsefulBuf.h b/components/TARGET_PSA/services/attestation/qcbor/inc/UsefulBuf.h deleted file mode 100644 index fa17b6c..0000000 --- a/components/TARGET_PSA/services/attestation/qcbor/inc/UsefulBuf.h +++ /dev/null @@ -1,1536 +0,0 @@ -/*============================================================================== - Copyright (c) 2016-2018, The Linux Foundation. - Copyright (c) 2018-2019, Laurence Lundblade. - All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of The Linux Foundation nor the names of its - contributors, nor the name "Laurence Lundblade" may be used to - endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED -WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT -ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS -BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE -OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN -IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ==============================================================================*/ - -/*=================================================================================== - FILE: UsefulBuf.h - - DESCRIPTION: General purpose input and output buffers - - EDIT HISTORY FOR FILE: - - This section contains comments describing changes made to the module. - Notice that changes are listed in reverse chronological order. - - when who what, where, why - -------- ---- --------------------------------------------------- - 12/17/2018 llundblade Remove const from UsefulBuf and UsefulBufC .len - 12/13/2018 llundblade Documentation improvements - 09/18/2018 llundblade Cleaner distinction between UsefulBuf and UsefulBufC - 02/02/18 llundbla Full support for integers in and out; fix pointer - alignment bug. Incompatible change: integers in/out - are now in network byte order. - 08/12/17 llundbla Added UsefulOutBuf_AtStart and UsefulBuf_Find - 06/27/17 llundbla Fix UsefulBuf_Compare() bug. Only affected comparison - for < or > for unequal length buffers. Added - UsefulBuf_Set() function. - 05/30/17 llundbla Functions for NULL UsefulBufs and const / unconst - 11/13/16 llundbla Initial Version. - - - =====================================================================================*/ - -#ifndef _UsefulBuf_h -#define _UsefulBuf_h - - -#include // for uint8_t, uint16_t.... -#include // for strlen, memcpy, memmove, memset -#include // for size_t - -/** - @file UsefulBuf.h - - The goal of this code is to make buffer and pointer manipulation - easier and safer when working with binary data. - - You use the UsefulBuf, UsefulOutBuf and UsefulInputBuf - structures to represent buffers rather than ad hoc pointers and lengths. - - With these it will often be possible to write code that does little or no - direct pointer manipulation for copying and formatting data. For example - the QCBOR encoder was rewritten using these and has no direct pointer - manipulation. - - While it is true that object code using these functions will be a little - larger and slower than a white-knuckle clever use of pointers might be, but - not by that much or enough to have an affect for most use cases. For - security-oriented code this is highly worthwhile. Clarity, simplicity, - reviewability and are more important. - - There are some extra sanity and double checks in this code to help catch - coding errors and simple memory corruption. They are helpful, but not a - substitute for proper code review, input validation and such. - - This code consists of a lot of inline functions and a few that are not. - It should not generate very much object code, especially with the - optimizer turned up to -Os or -O3. The idea is that the inline - functions are easier to review and understand and the optimizer does - the work of making the code small. - */ - - -/*...... This is a ruler that is 80 characters long...........................*/ - -/** - UsefulBufC and UsefulBuf are simple data structures to hold a pointer and - length for a binary data. In C99 this data structure can be passed on the - stack making a lot of code cleaner than carrying around a pointer and - length as two parameters. - - This is also conducive to secure code practice as the lengths are - always carried with the pointer and the convention for handling a - pointer and a length is clear. - - While it might be possible to write buffer and pointer code more - efficiently in some use cases, the thought is that unless there is an - extreme need for performance (e.g., you are building a gigabit-per-second - IP router), it is probably better to have cleaner code you can be most - certain about the security of. - - The non-const UsefulBuf is usually used to refer a buffer to be filled in. - The length is the size of the buffer. - - The const UsefulBufC is usually used to refer to some data that has been - filled in. The length is amount of valid data pointed to. - - A common use is to pass a UsefulBuf to a function, the function fills it - in, the function returns a UsefulBufC. The pointer is the same in both. - - A UsefulBuf is NULL, it has no value, when the ptr in it is NULL. - - There are utility functions for the following: - - Checking for UsefulBufs that are NULL, empty or both - - Copying, copying with offset, copying head or tail - - Comparing and finding substrings - - Initializating - - Create initialized const UsefulBufC from compiler literals - - Create initialized const UsefulBufC from NULL-terminated string - - Make an empty UsefulBuf on the stack - - See also UsefulOutBuf. It is a richer structure that has both the size of - the valid data and the size of the buffer. - - UsefulBuf is only 16 or 8 bytes on a 64- or 32-bit machine so it can go - on the stack and be a function parameter or return value. - - UsefulBuf is kind of like the Useful Pot Pooh gave Eeyore on his birthday. - Eeyore's balloon fits beautifully, "it goes in and out like anything". - -*/ -typedef struct useful_buf_c { - const void *ptr; - size_t len; -} UsefulBufC; - - -/** - The non-const UsefulBuf typically used for some allocated memory - that is to be filled in. The len is the amount of memory, - not the length of the valid data in the buffer. - */ -typedef struct useful_buf { - void *ptr; - size_t len; -} UsefulBuf; - - -/** - A "NULL" UsefulBufC is one that has no value in the same way a NULL pointer has no value. - A UsefulBuf is NULL when the ptr field is NULL. It doesn't matter what len is. - See UsefulBuf_IsEmpty() for the distinction between NULL and empty. - */ -#define NULLUsefulBufC ((UsefulBufC) {NULL, 0}) - -/** A NULL UsefulBuf is one that has no memory associated the say way - NULL points to nothing. It does not matter what len is. - */ -#define NULLUsefulBuf ((UsefulBuf) {NULL, 0}) - - -/** - @brief Check if a UsefulBuf is NULL or not - - @param[in] UB The UsefulBuf to check - - @return 1 if it is NULL, 0 if not. - */ -static inline int UsefulBuf_IsNULL(UsefulBuf UB) { - return !UB.ptr; -} - - -/** - @brief Check if a UsefulBufC is NULL or not - - @param[in] UB The UsefulBufC to check - - @return 1 if it is NULL, 0 if not. - */ -static inline int UsefulBuf_IsNULLC(UsefulBufC UB) { - return !UB.ptr; -} - - -/** - @brief Check if a UsefulBuf is empty or not - - @param[in] UB The UsefulBuf to check - - @return 1 if it is empty, 0 if not. - - An "Empty" UsefulBuf is one that has a value and can be considered to be set, - but that value is of zero length. It is empty when len is zero. It - doesn't matter what the ptr is. - - A lot of uses will not need to clearly distinguish a NULL UsefulBuf - from an empty one and can have the ptr NULL and the len 0. However - if a use of UsefulBuf needs to make a distinction then ptr should - not be NULL when the UsefulBuf is considered empty, but not NULL. - - */ -static inline int UsefulBuf_IsEmpty(UsefulBuf UB) { - return !UB.len; -} - - -/** - @brief Check if a UsefulBufC is empty or not - - @param[in] UB The UsefulBufC to check - - @return 1 if it is empty, 0 if not. - */ -static inline int UsefulBuf_IsEmptyC(UsefulBufC UB) { - return !UB.len; -} - - -/** - @brief Check if a UsefulBuf is NULL or empty - - @param[in] UB The UsefulBuf to check - - @return 1 if it is either NULL or empty, 0 if not. - */ -static inline int UsefulBuf_IsNULLOrEmpty(UsefulBuf UB) { - return UsefulBuf_IsEmpty(UB) || UsefulBuf_IsNULL(UB); -} - - -/** - @brief Check if a UsefulBufC is NULL or empty - - @param[in] UB The UsefulBufC to check - - @return 1 if it is either NULL or empty, 0 if not. - */ -static inline int UsefulBuf_IsNULLOrEmptyC(UsefulBufC UB) { - return UsefulBuf_IsEmptyC(UB) || UsefulBuf_IsNULLC(UB); -} - - -/** - @brief Convert a non const UsefulBuf to a const UsefulBufC - - @param[in] UB The UsefulBuf to convert - - Returns: a UsefulBufC struct - */ - -static inline UsefulBufC UsefulBuf_Const(const UsefulBuf UB) -{ - return (UsefulBufC){UB.ptr, UB.len}; -} - - -/** - @brief Convert a const UsefulBufC to a non-const UsefulBuf - - @param[in] UBC The UsefulBuf to convert - - Returns: a non const UsefulBuf struct - */ -static inline UsefulBuf UsefulBuf_Unconst(const UsefulBufC UBC) -{ - return (UsefulBuf){(void *)UBC.ptr, UBC.len}; -} - - -/** - Convert a literal string to a UsefulBufC. - - szString must be a literal string that you can take sizeof. - This is better for literal strings than UsefulBuf_FromSZ() - because it generates less code. It will not work on - non-literal strings. - - The terminating \0 (NULL) is NOT included in the length! - - */ -#define UsefulBuf_FROM_SZ_LITERAL(szString) \ - ((UsefulBufC) {(szString), sizeof(szString)-1}) - - -/** - Convert a literal byte array to a UsefulBufC. - - pBytes must be a literal string that you can take sizeof. - It will not work on non-literal arrays. - - */ -#define UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pBytes) \ - ((UsefulBufC) {(pBytes), sizeof(pBytes)}) - - -/** - Make an automatic variable with name of type UsefulBuf and point it to a stack - variable of the give size - */ -#define UsefulBuf_MAKE_STACK_UB(name, size) \ - uint8_t __pBuf##name[(size)];\ - UsefulBuf name = {__pBuf##name , sizeof( __pBuf##name )} - - -/** - Make a byte array in to a UsefulBuf - */ -#define UsefulBuf_FROM_BYTE_ARRAY(pBytes) \ - ((UsefulBuf) {(pBytes), sizeof(pBytes)}) - -/** - @brief Convert a NULL terminated string to a UsefulBufC. - - @param[in] szString The string to convert - - @return a UsefulBufC struct - - UsefulBufC.ptr points to the string so it's lifetime - must be maintained. - - The terminating \0 (NULL) is NOT included in the length! - - */ -static inline UsefulBufC UsefulBuf_FromSZ(const char *szString){ - return ((UsefulBufC) {szString, strlen(szString)}); -} - - -/** - @brief Copy one UsefulBuf into another at an offset - - @param[in] Dest Destiation buffer to copy into - @param[in] uOffset The byte offset in Dest at which to copy to - @param[in] Src The bytes to copy - - @return Pointer and length of the copy - - This fails and returns NULLUsefulBufC Src.len + uOffset > Dest.len. - - Like memcpy, there is no check for NULL. If NULL is passed - this will crash. - - There is an assumption that there is valid data in Dest up to - uOffset as the resulting UsefulBufC returned starts - at the beginning of Dest and goes to Src.len + uOffset. - - */ -UsefulBufC UsefulBuf_CopyOffset(UsefulBuf Dest, size_t uOffset, const UsefulBufC Src); - - -/** - @brief Copy one UsefulBuf into another - - @param[in] Dest The destination buffer to copy into - @param[out] Src The source to copy from - - @return filled in UsefulBufC on success, NULLUsefulBufC on failure - - This fails if Src.len is greater than Dest.len. - - Note that like memcpy, the pointers are not checked and - this will crash, rather than return NULLUsefulBufC if - they are NULL or invalid. - - Results are undefined if Dest and Src overlap. - - */ -static inline UsefulBufC UsefulBuf_Copy(UsefulBuf Dest, const UsefulBufC Src) { - return UsefulBuf_CopyOffset(Dest, 0, Src); -} - - -/** - @brief Set all bytes in a UsefulBuf to a value, for example 0 - - @param[in] pDest The destination buffer to copy into - @param[in] value The value to set the bytes to - - Note that like memset, the pointer in pDest is not checked and - this will crash if NULL or invalid. - - */ -static inline UsefulBufC UsefulBuf_Set(UsefulBuf pDest, uint8_t value) -{ - memset(pDest.ptr, value, pDest.len); - return (UsefulBufC){pDest.ptr, pDest.len}; -} - - -/** - @brief Copy a pointer into a UsefulBuf - - @param[in,out] Dest The destination buffer to copy into - @param[in] ptr The source to copy from - @param[in] len Length of the source; amoutn to copy - - @return 0 on success, 1 on failure - - This fails and returns NULLUsefulBufC if len is greater than - pDest->len. - - Note that like memcpy, the pointers are not checked and - this will crash, rather than return 1 if they are NULL - or invalid. - - */ -inline static UsefulBufC UsefulBuf_CopyPtr(UsefulBuf Dest, const void *ptr, size_t len) -{ - return UsefulBuf_Copy(Dest, (UsefulBufC){ptr, len}); -} - - -/** - @brief Returns a truncation of a UsefulBufC - - @param[in] UB The buffer to get the head of - @param[in] uAmount The number of bytes in the head - - @return A UsefulBufC that is the head of UB - - */ -static inline UsefulBufC UsefulBuf_Head(UsefulBufC UB, size_t uAmount) -{ - if(uAmount > UB.len) { - return NULLUsefulBufC; - } - return (UsefulBufC){UB.ptr, uAmount}; -} - - -/** - @brief Returns bytes from the end of a UsefulBufC - - @param[in] UB The buffer to get the tail of - @param[in] uAmount The offset from the start where the tail is to begin - - @return A UsefulBufC that is the tail of UB or NULLUsefulBufC if - uAmount is greater than the length of the UsefulBufC - - If the input UsefulBufC is NULL, but the len is not, then the - length of the tail will be calculated and returned along - with a NULL ptr. - */ -static inline UsefulBufC UsefulBuf_Tail(UsefulBufC UB, size_t uAmount) -{ - UsefulBufC ReturnValue; - - if(uAmount > UB.len) { - ReturnValue = NULLUsefulBufC; - } else if(UB.ptr == NULL) { - ReturnValue = (UsefulBufC){NULL, UB.len - uAmount}; - } else { - ReturnValue = (UsefulBufC){(uint8_t *)UB.ptr + uAmount, UB.len - uAmount}; - } - - return ReturnValue; -} - - -/** - @brief Compare two UsefulBufCs - - @param[in] UB1 The destination buffer to copy into - @param[in] UB2 The source to copy from - - @return 0 if equal... - - Returns a negative value if UB1 if is less than UB2. UB1 is - less than UB2 if it is shorter or the first byte that is not - the same is less. - - Returns 0 if the UsefulBufs are the same. - - Returns a positive value if UB2 is less than UB1. - - All that is of significance is that the result is positive, - negative or 0. (This doesn't return the difference between - the first non-matching byte like memcmp). - - */ -int UsefulBuf_Compare(const UsefulBufC UB1, const UsefulBufC UB2); - - -/** - @brief Find one UsefulBuf in another - - @param[in] BytesToSearch UsefulBuf to search through - @param[in] BytesToFind UsefulBuf with bytes to be found - - @return position of found bytes or SIZE_MAX if not found. - - */ -size_t UsefulBuf_FindBytes(UsefulBufC BytesToSearch, UsefulBufC BytesToFind); - - - - -#if 0 // NOT_DEPRECATED -/** Deprecated macro; use UsefulBuf_FROM_SZ_LITERAL instead */ -#define SZLiteralToUsefulBufC(szString) \ - ((UsefulBufC) {(szString), sizeof(szString)-1}) - -/** Deprecated macro; use UsefulBuf_MAKE_STACK_UB instead */ -#define MakeUsefulBufOnStack(name, size) \ - uint8_t __pBuf##name[(size)];\ - UsefulBuf name = {__pBuf##name , sizeof( __pBuf##name )} - -/** Deprecated macro; use UsefulBuf_FROM_BYTE_ARRAY_LITERAL instead */ -#define ByteArrayLiteralToUsefulBufC(pBytes) \ - ((UsefulBufC) {(pBytes), sizeof(pBytes)}) - -/** Deprecated function; use UsefulBuf_Unconst() instead */ -static inline UsefulBuf UsefulBufC_Unconst(const UsefulBufC UBC) -{ - return (UsefulBuf){(void *)UBC.ptr, UBC.len}; -} -#endif - - - -/* - Convenient functions to avoid type punning, compiler warnings and such - The optimizer reduces them to a simple assignment - This is a crusty corner of C. It shouldn't be this hard. - */ -static inline uint32_t UsefulBufUtil_CopyFloatToUint32(float f) -{ - uint32_t u32; - memcpy(&u32, &f, sizeof(uint32_t)); - return u32; -} - -static inline uint64_t UsefulBufUtil_CopyDoubleToUint64(double d) -{ - uint64_t u64; - memcpy(&u64, &d, sizeof(uint64_t)); - return u64; -} - -static inline double UsefulBufUtil_CopyUint64ToDouble(uint64_t u64) -{ - double d; - memcpy(&d, &u64, sizeof(uint64_t)); - return d; -} - -static inline float UsefulBufUtil_CopyUint32ToFloat(uint32_t u32) -{ - float f; - memcpy(&f, &u32, sizeof(uint32_t)); - return f; -} - - - - - -/** - UsefulOutBuf is a structure and functions (an object) that are good - for serializing data into a buffer such as is often done with network - protocols or data written to files. - - The main idea is that all the pointer manipulation for adding data is - done by UsefulOutBuf functions so the caller doesn't have to do any. - All the pointer manipulation is centralized here. This code will - have been reviewed and written carefully so it spares the caller of - much of this work and results in much safer code with much less work. - - The functions to add data to the output buffer always check the - length and will never write off the end of the output buffer. If an - attempt to add data that will not fit is made, an internal error flag - will be set and further attempts to add data will not do anything. - - Basically, if you initialized with the correct buffer, there is no - way to ever write off the end of that buffer when calling the Add - and Insert functions here. - - The functions to add data do not return an error. The working model - is that the caller just makes all the calls to add data without any - error checking on each one. The error is instead checked after all the - data is added when the result is to be used. This makes the caller's - code cleaner. - - There is a utility function to get the error status anytime along the - way if the caller wants. There are functions to see how much room is - left and see if some data will fit too, but their use is generally - not necessary. - - The general call flow is like this: - - - Initialize the UsefulOutBuf with the buffer that is to have the - data added. The caller allocates the buffer. It can be heap - or stack or shared memory (or other). - - - Make calls to add data to the output buffer. Insert and append - are both supported. The append and insert calls will never write - off the end of the buffer. - - - When all data is added, check the error status to make sure - everything fit. - - - Get the resulting serialized data either as a UsefulBuf (a - pointer and length) or have it copied to another buffer. - - UsefulOutBuf can be initialized with just a buffer length by passing - NULL as the pointer to the output buffer. This is useful if you want - to go through the whole serialization process to either see if it - will fit into a given buffer or compute the size of the buffer - needed. Pass a very large buffer size when calling Init, if you want - just to compute the size. - - Some inexpensive simple sanity checks are performed before every data - addition to guard against use of an uninitialized or corrupted - UsefulOutBuf. - - This has been used to create a CBOR encoder. The CBOR encoder has - almost no pointer manipulation in it, is much easier to read, and - easier to review. - - A UsefulOutBuf is 27 bytes or 15 bytes on 64- or 32-bit machines so it - can go on the stack or be a C99 function parameter. - */ - -typedef struct useful_out_buf { - UsefulBuf UB; // Memory that is being output to - size_t data_len; // length of the data - uint16_t magic; // Used to detect corruption and lack of initialization - uint8_t err; -} UsefulOutBuf; - - -/** - @brief Initialize and supply the actual output buffer - - @param[out] me The UsefulOutBuf to initialize - @param[in] Storage Buffer to output into - - Intializes the UsefulOutBuf with storage. Sets the current position - to the beginning of the buffer clears the error. - - This must be called before the UsefulOutBuf is used. - */ -void UsefulOutBuf_Init(UsefulOutBuf *me, UsefulBuf Storage); - - - - -/** Convenience marco to make a UsefulOutBuf on the stack and - initialize it with stack buffer - */ -#define UsefulOutBuf_MakeOnStack(name, size) \ - uint8_t __pBuf##name[(size)];\ - UsefulOutBuf name;\ - UsefulOutBuf_Init(&(name), (UsefulBuf){__pBuf##name, (size)}); - - - -/** - @brief Reset a UsefulOutBuf for re use - - @param[in] me Pointer to the UsefulOutBuf - - This sets the amount of data in the output buffer to none and - clears the error state. - - The output buffer is still the same one and size as from the - UsefulOutBuf_Init() call. - - It doesn't zero the data, just resets to 0 bytes of valid data. - */ -static inline void UsefulOutBuf_Reset(UsefulOutBuf *me) -{ - me->data_len = 0; - me->err = 0; -} - - -/** - @brief Returns position of end of data in the UsefulOutBuf - - @param[in] me Pointer to the UsefulOutBuf - - @return position of end of data - - On a freshly initialized UsefulOutBuf with no data added, this will - return 0. After ten bytes have been added, it will return 10 and so - on. - - Generally callers will not need this function for most uses of - UsefulOutBuf. - - */ -static inline size_t UsefulOutBuf_GetEndPosition(UsefulOutBuf *me) -{ - return me->data_len; -} - - -/** - @brief Returns whether any data has been added to the UsefulOutBuf - - @param[in] me Pointer to the UsefulOutBuf - - @return 1 if output position is at start - - */ -static inline int UsefulOutBuf_AtStart(UsefulOutBuf *me) -{ - return 0 == me->data_len; -} - - -/** - @brief Inserts bytes into the UsefulOutBuf - - @param[in] me Pointer to the UsefulOutBuf - @param[in] NewData UsefulBuf with the bytes to insert - @param[in] uPos Index in output buffer at which to insert - - NewData is the pointer and length for the bytes to be added to the - output buffer. There must be room in the output buffer for all of - NewData or an error will occur. - - The insertion point must be between 0 and the current valid data. If - not an error will occur. Appending data to the output buffer is - achieved by inserting at the end of the valid data. This can be - retrieved by calling UsefulOutBuf_GetEndPosition(). - - When insertion is performed, the bytes between the insertion point and - the end of data previously added to the output buffer is slid to the - right to make room for the new data. - - Overlapping buffers are OK. NewData can point to data in the output - buffer. - - If an error occurs an error state is set in the UsefulOutBuf. No - error is returned. All subsequent attempts to add data will do - nothing. - - Call UsefulOutBuf_GetError() to find out if there is an error. This - is usually not needed until all additions of data are complete. - - */ -void UsefulOutBuf_InsertUsefulBuf(UsefulOutBuf *me, UsefulBufC NewData, size_t uPos); - - -/** - @brief Insert a data buffer into the UsefulOutBuf - - @param[in] me Pointer to the UsefulOutBul - @param[in] pBytes Pointer to the bytes to insert - @param[in] uLen Length of the bytes to insert - @param[in] uPos Index in output buffer at which to insert - - See UsefulOutBuf_InsertUsefulBuf() for details. This is the same with - the difference being a pointer and length is passed in rather than an - UsefulBuf. - - */ -static inline void UsefulOutBuf_InsertData(UsefulOutBuf *me, const void *pBytes, size_t uLen, size_t uPos) -{ - UsefulBufC Data = {pBytes, uLen}; - UsefulOutBuf_InsertUsefulBuf(me, Data, uPos); -} - - -/** - @brief Insert a NULL-terminated string into the UsefulOutBuf - - @param[in] me Pointer to the UsefulOutBuf - @param[in] szString string to append - - */ -static inline void UsefulOutBuf_InsertString(UsefulOutBuf *me, const char *szString, size_t uPos) -{ - UsefulOutBuf_InsertUsefulBuf(me, (UsefulBufC){szString, strlen(szString)}, uPos); -} - - -/** - @brief Insert a byte into the UsefulOutBuf - - @param[in] me Pointer to the UsefulOutBul - @param[in] byte Bytes to insert - @param[in] uPos Index in output buffer at which to insert - - See UsefulOutBuf_InsertUsefulBuf() for details. This is the same with - the difference being a single byte is to be inserted. - */ -static inline void UsefulOutBuf_InsertByte(UsefulOutBuf *me, uint8_t byte, size_t uPos) -{ - UsefulOutBuf_InsertData(me, &byte, 1, uPos); -} - - -/** - @brief Insert a 16-bit integer into the UsefulOutBuf - - @param[in] me Pointer to the UsefulOutBul - @param[in] uInteger16 Integer to insert - @param[in] uPos Index in output buffer at which to insert - - See UsefulOutBuf_InsertUsefulBuf() for details. This is the same with - the difference being a single byte is to be inserted. - - The integer will be inserted in network byte order (big endian) - */ -static inline void UsefulOutBuf_InsertUint16(UsefulOutBuf *me, uint16_t uInteger16, size_t uPos) -{ - // Converts native integer format to network byte order (big endian) - uint8_t tmp[2]; - tmp[0] = (uInteger16 & 0xff00) >> 8; - tmp[1] = (uInteger16 & 0xff); - UsefulOutBuf_InsertData(me, tmp, 2, uPos); -} - - -/** - @brief Insert a 32-bit integer into the UsefulOutBuf - - @param[in] me Pointer to the UsefulOutBul - @param[in] uInteger32 Integer to insert - @param[in] uPos Index in output buffer at which to insert - - See UsefulOutBuf_InsertUsefulBuf() for details. This is the same with - the difference being a single byte is to be inserted. - - The integer will be inserted in network byte order (big endian) - */ -static inline void UsefulOutBuf_InsertUint32(UsefulOutBuf *me, uint32_t uInteger32, size_t uPos) -{ - // Converts native integer format to network byte order (big endian) - uint8_t tmp[4]; - tmp[0] = (uInteger32 & 0xff000000) >> 24; - tmp[1] = (uInteger32 & 0xff0000) >> 16; - tmp[2] = (uInteger32 & 0xff00) >> 8; - tmp[3] = (uInteger32 & 0xff); - UsefulOutBuf_InsertData(me, tmp, 4, uPos); -} - - -/** - @brief Insert a 64-bit integer into the UsefulOutBuf - - @param[in] me Pointer to the UsefulOutBul - @param[in] uInteger64 Integer to insert - @param[in] uPos Index in output buffer at which to insert - - See UsefulOutBuf_InsertUsefulBuf() for details. This is the same with - the difference being a single byte is to be inserted. - - The integer will be inserted in network byte order (big endian) - */ -static inline void UsefulOutBuf_InsertUint64(UsefulOutBuf *me, uint64_t uInteger64, size_t uPos) -{ - // Converts native integer format to network byte order (big endian) - uint8_t tmp[8]; - tmp[0] = (uInteger64 & 0xff00000000000000) >> 56; - tmp[1] = (uInteger64 & 0xff000000000000) >> 48; - tmp[2] = (uInteger64 & 0xff0000000000) >> 40; - tmp[3] = (uInteger64 & 0xff00000000) >> 32; - tmp[4] = (uInteger64 & 0xff000000) >> 24; - tmp[5] = (uInteger64 & 0xff0000) >> 16; - tmp[6] = (uInteger64 & 0xff00) >> 8; - tmp[7] = (uInteger64 & 0xff); - UsefulOutBuf_InsertData(me, tmp, 8, uPos); -} - - -/** - @brief Insert a float into the UsefulOutBuf - - @param[in] me Pointer to the UsefulOutBul - @param[in] f Integer to insert - @param[in] uPos Index in output buffer at which to insert - - See UsefulOutBuf_InsertUsefulBuf() for details. This is the same with - the difference being a single byte is to be inserted. - - The float will be inserted in network byte order (big endian) - */ -static inline void UsefulOutBuf_InsertFloat(UsefulOutBuf *me, float f, size_t uPos) -{ - UsefulOutBuf_InsertUint32(me, UsefulBufUtil_CopyFloatToUint32(f), uPos); -} - - -/** - @brief Insert a double into the UsefulOutBuf - - @param[in] me Pointer to the UsefulOutBul - @param[in] d Integer to insert - @param[in] uPos Index in output buffer at which to insert - - See UsefulOutBuf_InsertUsefulBuf() for details. This is the same with - the difference being a single byte is to be inserted. - - The double will be inserted in network byte order (big endian) - */ -static inline void UsefulOutBuf_InsertDouble(UsefulOutBuf *me, double d, size_t uPos) -{ - UsefulOutBuf_InsertUint64(me, UsefulBufUtil_CopyDoubleToUint64(d), uPos); -} - - - -/** - Append a UsefulBuf into the UsefulOutBuf - - @param[in] me Pointer to the UsefulOutBuf - @param[in] NewData UsefulBuf with the bytes to append - - See UsefulOutBuf_InsertUsefulBuf() for details. This does the same - with the insertion point at the end of the valid data. - -*/ -static inline void UsefulOutBuf_AppendUsefulBuf(UsefulOutBuf *me, UsefulBufC NewData) -{ - // An append is just a insert at the end - UsefulOutBuf_InsertUsefulBuf(me, NewData, UsefulOutBuf_GetEndPosition(me)); -} - - -/** - Append bytes to the UsefulOutBuf - - @param[in] me Pointer to the UsefulOutBuf - @param[in] pBytes Pointer to bytes to append - @param[in] uLen Index in output buffer at which to append - - See UsefulOutBuf_InsertUsefulBuf() for details. This does the same - with the insertion point at the end of the valid data. - */ - -static inline void UsefulOutBuf_AppendData(UsefulOutBuf *me, const void *pBytes, size_t uLen) -{ - UsefulBufC Data = {pBytes, uLen}; - UsefulOutBuf_AppendUsefulBuf(me, Data); -} - - -/** - Append a NULL-terminated string to the UsefulOutBuf - - @param[in] me Pointer to the UsefulOutBuf - @param[in] szString string to append - - */ -static inline void UsefulOutBuf_AppendString(UsefulOutBuf *me, const char *szString) -{ - UsefulOutBuf_AppendUsefulBuf(me, (UsefulBufC){szString, strlen(szString)}); -} - - -/** - @brief Append a byte to the UsefulOutBuf - - @param[in] me Pointer to the UsefulOutBuf - @param[in] byte Bytes to append - - See UsefulOutBuf_InsertUsefulBuf() for details. This does the same - with the insertion point at the end of the valid data. - */ -static inline void UsefulOutBuf_AppendByte(UsefulOutBuf *me, uint8_t byte) -{ - UsefulOutBuf_AppendData(me, &byte, 1); -} - -/** - @brief Append an integer to the UsefulOutBuf - - @param[in] me Pointer to the UsefulOutBuf - @param[in] uInteger16 Integer to append - - See UsefulOutBuf_InsertUsefulBuf() for details. This does the same - with the insertion point at the end of the valid data. - - The integer will be appended in network byte order (big endian). - */ -static inline void UsefulOutBuf_AppendUint16(UsefulOutBuf *me, uint16_t uInteger16){ - UsefulOutBuf_InsertUint16(me, uInteger16, UsefulOutBuf_GetEndPosition(me)); -} - -/** - @brief Append an integer to the UsefulOutBuf - - @param[in] me Pointer to the UsefulOutBuf - @param[in] uInteger32 Integer to append - - See UsefulOutBuf_InsertUsefulBuf() for details. This does the same - with the insertion point at the end of the valid data. - - The integer will be appended in network byte order (big endian). - */ -static inline void UsefulOutBuf_AppendUint32(UsefulOutBuf *me, uint32_t uInteger32){ - UsefulOutBuf_InsertUint32(me, uInteger32, UsefulOutBuf_GetEndPosition(me)); -} - -/** - @brief Append an integer to the UsefulOutBuf - - @param[in] me Pointer to the UsefulOutBuf - @param[in] uInteger64 Integer to append - - See UsefulOutBuf_InsertUsefulBuf() for details. This does the same - with the insertion point at the end of the valid data. - - The integer will be appended in network byte order (big endian). - */ -static inline void UsefulOutBuf_AppendUint64(UsefulOutBuf *me, uint64_t uInteger64){ - UsefulOutBuf_InsertUint64(me, uInteger64, UsefulOutBuf_GetEndPosition(me)); -} - - -/** - @brief Append a float to the UsefulOutBuf - - @param[in] me Pointer to the UsefulOutBuf - @param[in] f Float to append - - See UsefulOutBuf_InsertUsefulBuf() for details. This does the same - with the insertion point at the end of the valid data. - - The float will be appended in network byte order (big endian). - */ -static inline void UsefulOutBuf_AppendFloat(UsefulOutBuf *me, float f){ - UsefulOutBuf_InsertFloat(me, f, UsefulOutBuf_GetEndPosition(me)); -} - -/** - @brief Append a float to the UsefulOutBuf - - @param[in] me Pointer to the UsefulOutBuf - @param[in] d Double to append - - See UsefulOutBuf_InsertUsefulBuf() for details. This does the same - with the insertion point at the end of the valid data. - - The double will be appended in network byte order (big endian). - */ -static inline void UsefulOutBuf_AppendDouble(UsefulOutBuf *me, double d){ - UsefulOutBuf_InsertDouble(me, d, UsefulOutBuf_GetEndPosition(me)); -} - -/** - @brief Returns the current error status - - @param[in] me Pointer to the UsefulOutBuf - - @return 0 if all OK, 1 on error - - This is the error status since the call to either - UsefulOutBuf_Reset() of UsefulOutBuf_Init(). Once it goes into error - state it will stay until one of those functions is called. - - Possible error conditions are: - - bytes to be inserted will not fit - - insertion point is out of buffer or past valid data - - current position is off end of buffer (probably corruption or uninitialized) - - detect corruption / uninitialized by bad magic number - */ - -static inline int UsefulOutBuf_GetError(UsefulOutBuf *me) -{ - return me->err; -} - - -/** - @brief Returns number of bytes unused used in the output buffer - - @param[in] me Pointer to the UsefulOutBuf - - @return Number of unused bytes or zero - - Because of the error handling strategy and checks in UsefulOutBuf_InsertUsefulBuf() - it is usually not necessary to use this. - */ - -static inline size_t UsefulOutBuf_RoomLeft(UsefulOutBuf *me) -{ - return me->UB.len - me->data_len; -} - - -/** - @brief Returns true / false if some number of bytes will fit in the UsefulOutBuf - - @param[in] me Pointer to the UsefulOutBuf - @param[in] uLen Number of bytes for which to check - - @return 1 or 0 if nLen bytes would fit - - Because of the error handling strategy and checks in UsefulOutBuf_InsertUsefulBuf() - it is usually not necessary to use this. - */ - -static inline int UsefulOutBuf_WillItFit(UsefulOutBuf *me, size_t uLen) -{ - return uLen <= UsefulOutBuf_RoomLeft(me); -} - - -/** - @brief Returns the resulting valid data in a UsefulOutBuf - - @param[in] me Pointer to the UsefulOutBuf. - - @return The valid data in UsefulOutBuf. - - The storage for the returned data is Storage parameter passed - to UsefulOutBuf_Init(). See also UsefulOutBuf_CopyOut(). - - This can be called anytime and many times to get intermediate - results. It doesn't change the data or reset the current position - so you can keep adding data. - */ - -UsefulBufC UsefulOutBuf_OutUBuf(UsefulOutBuf *me); - - -/** - @brief Copies the valid data out into a supplied buffer - - @param[in] me Pointer to the UsefulOutBuf - @param[out] Dest The destination buffer to copy into - - @return Pointer and length of copied data. - - This is the same as UsefulOutBuf_OutUBuf() except it copies the data. -*/ - -UsefulBufC UsefulOutBuf_CopyOut(UsefulOutBuf *me, UsefulBuf Dest); - - - - - - - - - - - - - -/** - UsefulInputBuf is the counterpart to UsefulOutBuf and is for parsing - data read or received. Initialize it with the data - from the network and its length. Then use the functions - here to get the various data types out of it. It maintains a position - for getting the next item. This means you don't have to track a - pointer as you get each object. UsefulInputBuf does that for you and - makes sure it never goes off the end of the buffer. The QCBOR - implementation parser makes use of this for all its pointer math and - length checking. - - UsefulInputBuf also maintains an internal error state so you do not have - to. Once data has been requested off the end of the buffer, it goes - into an error state. You can keep calling functions to get more data - but they will either return 0 or NULL. As long as you don't - dereference the NULL, you can wait until all data items have been - fetched before checking for the error and this can simplify your - code. - - The integer and float parsing expects network byte order (big endian). - Network byte order is what is used by TCP/IP, CBOR and most internet - protocols. - - Lots of inlining is used to keep code size down. The code optimizer, - particularly with the -Os, also reduces code size a lot. The only - non-inline code is UsefulInputBuf_GetBytes() which is less than 100 - bytes so use of UsefulInputBuf doesn't add much code for all the messy - hard-to-get right issues with parsing in C that is solves. - - The parse context size is: - 64-bit machine: 16 + 8 + 2 + 1 (5 bytes padding to align) = 32 bytes - 32-bit machine: 8 + 4 + 2 + 1 (1 byte padding to align) = 16 bytes - - */ - -#define UIB_MAGIC (0xB00F) - -typedef struct useful_input_buf { - // Private data structure - UsefulBufC UB; // Data being parsed - size_t cursor; // Current offset in data being parse - uint16_t magic; // Check for corrupted or uninitialized UsefulInputBuf - uint8_t err; // Set request goes off end or magic number is bad -} UsefulInputBuf; - - - -/** - @brief Initialize the UsefulInputBuf structure before use. - - @param[in] me Pointer to the UsefulInputBuf instance. - @param[in] UB Pointer to the data to parse. - - */ -static inline void UsefulInputBuf_Init(UsefulInputBuf *me, UsefulBufC UB) -{ - me->cursor = 0; - me->err = 0; - me->magic = UIB_MAGIC; - me->UB = UB; -} - - -/** - @brief Returns current position in input buffer - - @param[in] me Pointer to the UsefulInputBuf. - - @return Integer position of the cursor - - The position that the next bytes will be returned from. - - */ -static inline size_t UsefulInputBuf_Tell(UsefulInputBuf *me) -{ - return me->cursor; -} - - -/** - @brief Sets current position in input buffer - - @param[in] me Pointer to the UsefulInputBuf. - @param[in] uPos Position to set to - - If the position is off the end of the input buffer, the error state - is entered and all functions will do nothing. - - Seeking to a valid position in the buffer will not reset the error - state. Only re initialization will do that. - - */ -static inline void UsefulInputBuf_Seek(UsefulInputBuf *me, size_t uPos) -{ - if(uPos > me->UB.len) { - me->err = 1; - } else { - me->cursor = uPos; - } -} - - -/** - @brief Returns the number of bytes from the cursor to the end of the buffer, - the uncomsummed bytes. - - @param[in] me Pointer to the UsefulInputBuf. - - @return number of bytes unconsumed or 0 on error. - - This is a critical function for input length validation. This does - some pointer / offset math. - - Returns 0 if the cursor it invalid or corruption of the structure is - detected. - - Code Reviewers: THIS FUNCTION DOES POINTER MATH - */ -static inline size_t UsefulInputBuf_BytesUnconsumed(UsefulInputBuf *me) -{ - // Magic number is messed up. Either the structure got overwritten - // or was never initialized. - if(me->magic != UIB_MAGIC) { - return 0; - } - - // The cursor is off the end of the input buffer given - // Presuming there are no bugs in this code, this should never happen. - // If it so, the struct was corrupted. The check is retained as - // as a defense in case there is a bug in this code or the struct is corrupted. - if(me->cursor > me->UB.len) { - return 0; - } - - // subtraction can't go neative because of check above - return me->UB.len - me->cursor; -} - - -/** - @brief Check if there are any unconsumed bytes - - @param[in] me Pointer to the UsefulInputBuf. - - @return 1 if len bytes are available after the cursor, and 0 if not - - */ -static inline int UsefulInputBuf_BytesAvailable(UsefulInputBuf *me, size_t uLen) -{ - return UsefulInputBuf_BytesUnconsumed(me) >= uLen ? 1 : 0; -} - - -/** - @brief Get pointer to bytes out of the input buffer - - @param[in] me Pointer to the UsefulInputBuf. - @param[in] uNum Number of bytes to get - - @return Pointer to bytes. - - This consumes n bytes from the input buffer. It returns a pointer to - the start of the n bytes. - - If there are not n bytes in the input buffer, NULL will be returned - and an error will be set. - - It advances the current position by n bytes. - */ -const void * UsefulInputBuf_GetBytes(UsefulInputBuf *me, size_t uNum); - - -/** - @brief Get UsefulBuf out of the input buffer - - @param[in] me Pointer to the UsefulInputBuf. - @param[in] uNum Number of bytes to get - - @return UsefulBufC with ptr and length for bytes consumed. - - This consumes n bytes from the input buffer and returns the pointer - and len to them as a UsefulBufC. The len returned will always be n. - - If there are not n bytes in the input buffer, UsefulBufC.ptr will be - NULL and UsefulBufC.len will be 0. An error will be set. - - It advances the current position by n bytes. - */ -static inline UsefulBufC UsefulInputBuf_GetUsefulBuf(UsefulInputBuf *me, size_t uNum) -{ - const void *pResult = UsefulInputBuf_GetBytes(me, uNum); - if(!pResult) { - return NULLUsefulBufC; - } else { - return (UsefulBufC){pResult, uNum}; - } -} - - -/** - @brief Get a byte out of the input buffer. - - @param[in] me Pointer to the UsefulInputBuf. - - @return The byte - - This consumes 1 byte from the input buffer. It returns the byte. - - If there is not 1 byte in the buffer, 0 will be returned for the byte - and an error set internally. You must check the error at some point - to know whether the 0 was the real value or just returned in error, - but you may not have to do that right away. Check the error state - with UsefulInputBuf_GetError(). You can also know you are in the - error state if UsefulInputBuf_GetBytes() returns NULL or the ptr from - UsefulInputBuf_GetUsefulBuf() is NULL. - - It advances the current position by 1 byte. - */ -static inline uint8_t UsefulInputBuf_GetByte(UsefulInputBuf *me) -{ - const void *pResult = UsefulInputBuf_GetBytes(me, sizeof(uint8_t)); - - return pResult ? *(uint8_t *)pResult : 0; -} - - -/** - @brief Get a uint16_t out of the input buffer - - @param[in] me Pointer to the UsefulInputBuf. - - @return The uint16_t - - See UsefulInputBuf_GetByte(). This works the same, except it returns - a uint16_t and two bytes are consumed. - - The input bytes must be in network order (big endian). - */ -static inline uint16_t UsefulInputBuf_GetUint16(UsefulInputBuf *me) -{ - const uint8_t *pResult = (const uint8_t *)UsefulInputBuf_GetBytes(me, sizeof(uint16_t)); - - if(!pResult) { - return 0; - } - - return ((uint16_t)pResult[0] << 8) + (uint16_t)pResult[1]; -} - - -/** - @brief Get a uint32_t out of the input buffer - - @param[in] me Pointer to the UsefulInputBuf. - - @return The uint32_t - - See UsefulInputBuf_GetByte(). This works the same, except it returns - a uint32_t and four bytes are consumed. - - The input bytes must be in network order (big endian). - */ -static inline uint32_t UsefulInputBuf_GetUint32(UsefulInputBuf *me) -{ - const uint8_t *pResult = (const uint8_t *)UsefulInputBuf_GetBytes(me, sizeof(uint32_t)); - - if(!pResult) { - return 0; - } - - return ((uint32_t)pResult[0]<<24) + - ((uint32_t)pResult[1]<<16) + - ((uint32_t)pResult[2]<<8) + - (uint32_t)pResult[3]; -} - - -/** - @brief Get a uint64_t out of the input buffer - - @param[in] me Pointer to the UsefulInputBuf. - - @return The uint64_t - - See UsefulInputBuf_GetByte(). This works the same, except it returns - a uint64_t and eight bytes are consumed. - - The input bytes must be in network order (big endian). - */ -static inline uint64_t UsefulInputBuf_GetUint64(UsefulInputBuf *me) -{ - const uint8_t *pResult = (const uint8_t *)UsefulInputBuf_GetBytes(me, sizeof(uint64_t)); - - if(!pResult) { - return 0; - } - - return ((uint64_t)pResult[0]<<56) + - ((uint64_t)pResult[1]<<48) + - ((uint64_t)pResult[2]<<40) + - ((uint64_t)pResult[3]<<32) + - ((uint64_t)pResult[4]<<24) + - ((uint64_t)pResult[5]<<16) + - ((uint64_t)pResult[6]<<8) + - (uint64_t)pResult[7]; -} - - -/** - @brief Get a float out of the input buffer - - @param[in] me Pointer to the UsefulInputBuf. - - @return The float - - See UsefulInputBuf_GetByte(). This works the same, except it returns - a float and four bytes are consumed. - - The input bytes must be in network order (big endian). - */ -static inline float UsefulInputBuf_GetFloat(UsefulInputBuf *me) -{ - uint32_t uResult = UsefulInputBuf_GetUint32(me); - - return uResult ? UsefulBufUtil_CopyUint32ToFloat(uResult) : 0; -} - -/** - @brief Get a double out of the input buffer - - @param[in] me Pointer to the UsefulInputBuf. - - @return The double - - See UsefulInputBuf_GetByte(). This works the same, except it returns - a double and eight bytes are consumed. - - The input bytes must be in network order (big endian). - */ -static inline double UsefulInputBuf_GetDouble(UsefulInputBuf *me) -{ - uint64_t uResult = UsefulInputBuf_GetUint64(me); - - return uResult ? UsefulBufUtil_CopyUint64ToDouble(uResult) : 0; -} - - -/** - @brief Get the error status - - @param[in] me Pointer to the UsefulInputBuf. - - @return The error. - - Zero is success, non-zero is error. Once in the error state, the only - way to clear it is to call Init again. - - You may be able to only check the error state at the end after all - the Get()'s have been done, but if what you get later depends on what - you get sooner you cannot. For example if you get a length or count - of following items you will have to check the error. - - */ -static inline int UsefulInputBuf_GetError(UsefulInputBuf *me) -{ - return me->err; -} - - -#endif // _UsefulBuf_h - - diff --git a/components/TARGET_PSA/services/attestation/qcbor/inc/qcbor.h b/components/TARGET_PSA/services/attestation/qcbor/inc/qcbor.h deleted file mode 100644 index f050988..0000000 --- a/components/TARGET_PSA/services/attestation/qcbor/inc/qcbor.h +++ /dev/null @@ -1,2598 +0,0 @@ -/*============================================================================== - Copyright (c) 2016-2018, The Linux Foundation. - Copyright (c) 2018-2019, Laurence Lundblade. - All rights reserved. - SPDX-License-Identifier: BSD-3-Clause - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of The Linux Foundation nor the names of its - contributors, nor the name "Laurence Lundblade" may be used to - endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED -WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT -ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS -BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE -OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN -IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ==============================================================================*/ - - -/*=================================================================================== - FILE: qcbor.h - - DESCRIPTION: This is the full public API and data structures for QCBOR - - EDIT HISTORY FOR FILE: - - This section contains comments describing changes made to the module. - Notice that changes are listed in reverse chronological order. - - when who what, where, why - -------- ---- --------------------------------------------------- - 12/18/18 llundblade Move decode malloc optional code to separate repository - 12/13/18 llundblade Documentatation improvements - 11/29/18 llundblade Rework to simpler handling of tags and labels. - 11/9/18 llundblade Error codes are now enums. - 11/1/18 llundblade Floating support. - 10/31/18 llundblade Switch to one license that is almost BSD-3. - 10/15/18 llundblade Indefinite length maps and arrays supported - 10/8/18 llundblade Indefinite length strings supported - 09/28/18 llundblade Added bstr wrapping feature for COSE implementation. - 07/05/17 llundbla Add bstr wrapping of maps/arrays for COSE. - 03/01/17 llundbla More data types; decoding improvements and fixes. - 11/13/16 llundbla Integrate most TZ changes back into github version. - 09/30/16 gkanike Porting to TZ. - 03/15/16 llundbla Initial Version. - - =====================================================================================*/ - -#ifndef __QCBOR__qcbor__ -#define __QCBOR__qcbor__ - -/*...... This is a ruler that is 80 characters long...........................*/ - -/* =========================================================================== - BEGINNING OF PRIVATE PART OF THIS FILE - - Caller of QCBOR should not reference any of the details below up until - the start of the public part. - =========================================================================== */ - -/* - Standard integer types are used in the interface to be precise about - sizes to be better at preventing underflow/overflow errors. - */ -#include -#include -#include "UsefulBuf.h" - - -/* - The maxium nesting of arrays and maps when encoding or decoding. - (Further down in the file there is a definition that refers to this - that is public. This is done this way so there can be a nice - separation of public and private parts in this file. -*/ -#define QCBOR_MAX_ARRAY_NESTING1 15 // Do not increase this over 255 - - -/* The largest offset to the start of an array or map. It is slightly - less than UINT32_MAX so the error condition can be tests on 32-bit machines. - UINT32_MAX comes from uStart in QCBORTrackNesting being a uin32_t. - - This will cause trouble on a machine where size_t is less than 32-bits. - */ -#define QCBOR_MAX_ARRAY_OFFSET (UINT32_MAX - 100) - -/* - PRIVATE DATA STRUCTURE - - Holds the data for tracking array and map nesting during encoding. Pairs up with - the Nesting_xxx functions to make an "object" to handle nesting encoding. - - uStart is a uint32_t instead of a size_t to keep the size of this - struct down so it can be on the stack without any concern. It would be about - double if size_t was used instead. - - Size approximation (varies with CPU/compiler): - 64-bit machine: (15 + 1) * (4 + 2 + 1 + 1 pad) + 8 = 136 bytes - 32-bit machine: (15 + 1) * (4 + 2 + 1 + 1 pad) + 4 = 132 bytes -*/ -typedef struct __QCBORTrackNesting { - // PRIVATE DATA STRUCTURE - struct { - // See function OpenArrayInternal() for detailed comments on how this works - uint32_t uStart; // uStart is the byte position where the array starts - uint16_t uCount; // Number of items in the arrary or map; counts items in a map, not pairs of items - uint8_t uMajorType; // Indicates if item is a map or an array - } pArrays[QCBOR_MAX_ARRAY_NESTING1+1], // stored state for the nesting levels - *pCurrentNesting; // the current nesting level -} QCBORTrackNesting; - - -/* - PRIVATE DATA STRUCTURE - - Context / data object for encoding some CBOR. Used by all encode functions to - form a public "object" that does the job of encdoing. - - Size approximation (varies with CPU/compiler): - 64-bit machine: 27 + 1 (+ 4 padding) + 136 = 32 + 136 = 168 bytes - 32-bit machine: 15 + 1 + 132 = 148 bytes -*/ -struct _QCBOREncodeContext { - // PRIVATE DATA STRUCTURE - UsefulOutBuf OutBuf; // Pointer to output buffer, its length and position in it - uint8_t uError; // Error state - QCBORTrackNesting nesting; // Keep track of array and map nesting -}; - - -/* - PRIVATE DATA STRUCTURE - - Holds the data for array and map nesting for decoding work. This structure - and the DecodeNesting_xxx functions form an "object" that does the work - for arrays and maps. - - Size approximation (varies with CPU/compiler): - 64-bit machine: 4 * 16 + 8 = 72 - 32-bit machine: 4 * 16 + 4 = 68 - */ -typedef struct __QCBORDecodeNesting { - // PRIVATE DATA STRUCTURE - struct { - uint16_t uCount; - uint8_t uMajorType; - } pMapsAndArrays[QCBOR_MAX_ARRAY_NESTING1+1], - *pCurrent; -} QCBORDecodeNesting; - - -/* - PRIVATE DATA STRUCTURE - - The decode context. This data structure plus the public QCBORDecode_xxx - functions form an "object" that does CBOR decoding. - - Size approximation (varies with CPU/compiler): - 64-bit machine: 32 + 1 + 1 + 6 bytes padding + 72 + 16 = 128 bytes - 32-bit machine: 16 + 1 + 1 + 2 bytes padding + 68 + 8 = 68 bytes - */ -struct _QCBORDecodeContext { - // PRIVATE DATA STRUCTURE - UsefulInputBuf InBuf; - - uint8_t uDecodeMode; - uint8_t bStringAllocateAll; - - QCBORDecodeNesting nesting; - - // This is NULL or points to a QCBORStringAllocator. It is void - // here because _QCBORDecodeContext is defined early in the - // private part of this file and QCBORStringAllocat is defined - // later in the public part of this file. - void *pStringAllocator; - - // This is NULL or points to QCBORTagList. - // It is type void for the same reason as above. - const void *pCallerConfiguredTagList; -}; - -// Used internally in the impementation here -// Must not conflict with any of the official CBOR types -#define CBOR_MAJOR_NONE_TYPE_RAW 9 -#define CBOR_MAJOR_NONE_TAG_LABEL_REORDER 10 - - -/* =========================================================================== - END OF PRIVATE PART OF THIS FILE - - BEGINNING OF PUBLIC PART OF THIS FILE - =========================================================================== */ - - - -/* =========================================================================== - BEGINNING OF CONSTANTS THAT COME FROM THE CBOR STANDARD, RFC 7049 - - It is not necessary to use these directly when encoding or decoding - CBOR with this implementation. - =========================================================================== */ - -/* Standard CBOR Major type for positive integers of various lengths */ -#define CBOR_MAJOR_TYPE_POSITIVE_INT 0 - -/* Standard CBOR Major type for negative integer of various lengths */ -#define CBOR_MAJOR_TYPE_NEGATIVE_INT 1 - -/* Standard CBOR Major type for an array of arbitrary 8-bit bytes. */ -#define CBOR_MAJOR_TYPE_BYTE_STRING 2 - -/* Standard CBOR Major type for a UTF-8 string. Note this is true 8-bit UTF8 - with no encoding and no NULL termination */ -#define CBOR_MAJOR_TYPE_TEXT_STRING 3 - -/* Standard CBOR Major type for an ordered array of other CBOR data items */ -#define CBOR_MAJOR_TYPE_ARRAY 4 - -/* Standard CBOR Major type for CBOR MAP. Maps an array of pairs. The - first item in the pair is the "label" (key, name or identfier) and the second - item is the value. */ -#define CBOR_MAJOR_TYPE_MAP 5 - -/* Standard CBOR optional tagging. This tags things like dates and URLs */ -#define CBOR_MAJOR_TYPE_OPTIONAL 6 - -/* Standard CBOR extra simple types like floats and the values true and false */ -#define CBOR_MAJOR_TYPE_SIMPLE 7 - - -/* - These are special values for the AdditionalInfo bits that are part of the first byte. - Mostly they encode the length of the data item. - */ -#define LEN_IS_ONE_BYTE 24 -#define LEN_IS_TWO_BYTES 25 -#define LEN_IS_FOUR_BYTES 26 -#define LEN_IS_EIGHT_BYTES 27 -#define ADDINFO_RESERVED1 28 -#define ADDINFO_RESERVED2 29 -#define ADDINFO_RESERVED3 30 -#define LEN_IS_INDEFINITE 31 - - -/* - 24 is a special number for CBOR. Integers and lengths - less than it are encoded in the same byte as the major type - */ -#define CBOR_TWENTY_FOUR 24 - - -/* - Tags that are used with CBOR_MAJOR_TYPE_OPTIONAL. These are - the ones defined in the CBOR spec. - */ -/** See QCBOREncode_AddDateString() below */ -#define CBOR_TAG_DATE_STRING 0 -/** See QCBOREncode_AddDateEpoch_2() */ -#define CBOR_TAG_DATE_EPOCH 1 -#define CBOR_TAG_POS_BIGNUM 2 -#define CBOR_TAG_NEG_BIGNUM 3 -#define CBOR_TAG_FRACTION 4 -#define CBOR_TAG_BIGFLOAT 5 - -#define CBOR_TAG_COSE_ENCRYPTO 16 -#define CBOR_TAG_COSE_MAC0 17 -#define CBOR_TAG_COSE_SIGN1 18 - -/* The data in byte string should be converted in base 64 URL when encoding in JSON or similar text-based representations */ -#define CBOR_TAG_ENC_AS_B64URL 21 -/* The data in byte string should be encoded in base 64 when encoding in JSON */ -#define CBOR_TAG_ENC_AS_B64 22 -/* The data in byte string should be encoded in base 16 when encoding in JSON */ -#define CBOR_TAG_ENC_AS_B16 23 -#define CBOR_TAG_CBOR 24 -/** The data in the string is a URIs, as defined in RFC3986 */ -#define CBOR_TAG_URI 32 -/** The data in the string is a base 64'd URL */ -#define CBOR_TAG_B64URL 33 -/** The data in the string is base 64'd */ -#define CBOR_TAG_B64 34 -/** regular expressions in Perl Compatible Regular Expressions (PCRE) / JavaScript syntax ECMA262. */ -#define CBOR_TAG_REGEX 35 -/** MIME messages (including all headers), as defined in RFC2045 */ -#define CBOR_TAG_MIME 36 -/** Binary UUID */ -#define CBOR_TAG_BIN_UUID 37 - -#define CBOR_TAG_CWT 61 - -#define CBOR_TAG_ENCRYPT 96 -#define CBOR_TAG_MAC 97 -#define CBOR_TAG_SIGN 98 - -#define CBOR_TAG_GEO_COORD 103 - - -/** The data is CBOR data */ -#define CBOR_TAG_CBOR_MAGIC 55799 -#define CBOR_TAG_NONE UINT64_MAX - - -/* - Values for the 5 bits for items of major type 7 - */ -#define CBOR_SIMPLEV_FALSE 20 -#define CBOR_SIMPLEV_TRUE 21 -#define CBOR_SIMPLEV_NULL 22 -#define CBOR_SIMPLEV_UNDEF 23 -#define CBOR_SIMPLEV_ONEBYTE 24 -#define HALF_PREC_FLOAT 25 -#define SINGLE_PREC_FLOAT 26 -#define DOUBLE_PREC_FLOAT 27 -#define CBOR_SIMPLE_BREAK 31 - - - -/* =========================================================================== - - END OF CONSTANTS THAT COME FROM THE CBOR STANDARD, RFC 7049 - - BEGINNING OF PUBLIC INTERFACE FOR QCBOR ENCODER / DECODER - - =========================================================================== */ - -/** - - @file qcbor.h - - Q C B O R E n c o d e / D e c o d e - - This implements CBOR -- Concise Binary Object Representation as defined - in RFC 7049. More info is at http://cbor.io. This is a near-complete - implementation of the specification. Limitations are listed further down. - - CBOR is intentionally designed to be translatable to JSON, but not - all CBOR can convert to JSON. See RFC 7049 for more info on how to - construct CBOR that is the most JSON friendly. - - The memory model for encoding and decoding is that encoded CBOR - must be in a contiguous buffer in memory. During encoding the - caller must supply an output buffer and if the encoding would go - off the end of the buffer an error is returned. During decoding - the caller supplies the encoded CBOR in a contiguous buffer - and the decoder returns pointers and lengths into that buffer - for strings. - - This implementation does not require malloc. All data structures - passed in/out of the APIs can fit on the stack. - - Decoding of indefinite length strings is a special case that requires - a "string allocator" to allocate memory into which the segments of - the string are coalesced. Without this, decoding will error out if - an indefinite length string is encountered (indefinite length maps - and arrays do not require the string allocator). A simple string - allocator called MemPool is built-in and will work if supplied with - a block of memory to allocate. The string allocator can optionally - use malloc() or some other custom scheme. - - Here are some terms and definitions: - - - "Item", "Data Item": An integer or string or such. The basic "thing" that - CBOR is about. An array is an item itself that contains some items. - - - "Array": An ordered sequence of items, the same as JSON. - - - "Map": A collection of label/value pairs. Each pair is a data - item. A JSON "object" is the same as a CBOR "map". - - - "Label": The data item in a pair in a map that names or identifies the - pair, not the value. This implementation refers to it as a "label". - JSON refers to it as the "name". The CBOR RFC refers to it this as a "key". - This implementation chooses label instead because key is too easily confused - with a cryptographic key. The COSE standard, which uses CBOR, has also - chosen to use the term "label" rather than "key" for this same reason. - - - "Key": See "Label" above. - - - "Tag": Optional info that can be added before each data item. This is always - CBOR major type 6. - - - "Initial Byte": The first byte of an encoded item. Encoding and decoding of - this byte is taken care of by the implementation. - - - "Additional Info": In addition to the major type, all data items have some - other info. This is usually the length of the data, but can be several - other things. Encoding and decoding of this is taken care of by the - implementation. - - CBOR has two mechanisms for tagging and labeling the data - values like integers and strings. For example, an integer that - represents someone's birthday in epoch seconds since Jan 1, 1970 - could be encoded like this: - - - First it is CBOR_MAJOR_TYPE_POSITIVE_INT, the primitive positive - integer. - - Next it has a "tag" CBOR_TAG_DATE_EPOCH indicating the integer - represents a date in the form of the number of seconds since - Jan 1, 1970. - - Last it has a string "label" like "BirthDate" indicating - the meaning of the data. - - The encoded binary looks like this: - a1 # Map of 1 item - 69 # Indicates text string of 9 bytes - 426972746844617465 # The text "BirthDate" - c1 # Tags next int as epoch date - 1a # Indicates 4 byte integer - 580d4172 # unsigned integer date 1477263730 - - Implementors using this API will primarily work with labels. Generally - tags are only needed for making up new data types. This implementation - covers most of the data types defined in the RFC using tags. It also, - allows for the creation of news tags if necessary. - - This implementation explicitly supports labels that are text strings - and integers. Text strings translate nicely into JSON objects and - are very readable. Integer labels are much less readable, but - can be very compact. If they are in the range of -23 to - 23 they take up only one byte. - - CBOR allows a label to be any type of data including an array or - a map. It is possible to use this API to construct and - parse such labels, but it is not explicitly supported. - - A common encoding usage mode is to invoke the encoding twice. First - with no output buffer to compute the length of the needed output - buffer. Then the correct sized output buffer is allocated. Last the - encoder is invoked again, this time with the output buffer. - - The double invocation is not required if the max output buffer size - can be predicted. This is usually possible for simple CBOR structures. - If the double invocation is implemented, it can be - in a loop or function as in the example code so that the code doesn't - have to actually be written twice, saving code size. - - If a buffer too small to hold the encoded output is given, the error - QCBOR_ERR_BUFFER_TOO_SMALL will be returned. Data will never be - written off the end of the output buffer no matter which functions - here are called or what parameters are passed to them. - - The error handling is simple. The only possible errors are trying to - encode structures that are too large or too complex. There are no - internal malloc calls so there will be no failures for out of memory. - Only the final call, QCBOREncode_Finish(), returns an error code. - Once an error happens, the encoder goes into an error state and calls - to it will do nothing so the encoding can just go on. An error - check is not needed after every data item is added. - - Encoding generally proceeds by calling QCBOREncode_Init(), calling - lots of "Add" functions and calling QCBOREncode_Finish(). There - are many "Add" functions for various data types. The input - buffers need only to be valid during the "Add" calls. The - data is copied into the output buf during the "Add" call. - - There are three `Add` functions for each data type. The first - / main one for the type is for adding the data item to an array. - The second one's name ends in `ToMap`, is used for adding - data items to maps and takes a string - argument that is its label in the map. The third one ends in - `ToMapN`, is also used for adding data items to maps, and - takes an integer argument that is its label in the map. - - The simplest aggregate type is an array, which is a simple ordered - set of items without labels the same as JSON arrays. Call - QCBOREncode_OpenArray() to open a new array, then "Add" to - put items in the array and then QCBOREncode_CloseArray(). Nesting - to a limit is allowed. All opens must be matched by closes or an - encoding error will be returned. - - The other aggregate type is a map which does use labels. The - `Add` functions that end in `ToMap` and `ToMapN` are convenient - ways to add labeled data items to a map. You can also call - any type of `Add` function once to add a label of any time and - then call any type of `Add` again to add its value. - - Note that when you nest arrays or maps in a map, the nested - array or map has a label. - - Usually it is not necessary to add tags explicitly as most - tagged types have functions here, but they can be added by - calling QCBOREncode_AddTag(). There is an IANA registry for new tags that are - for broad use and standardization as per RFC 7049. It is also - allowed for protocols to make up new tags in the range above 256. - Note that even arrays and maps can be tagged. - - Summary Limits of this implementation: - - The entire encoded CBOR must fit into contiguous memory. - - Max size of encoded / decoded CBOR data is UINT32_MAX (4GB). - - Max array / map nesting level when encoding / decoding is - QCBOR_MAX_ARRAY_NESTING (this is typically 15). - - Max items in an array or map when encoding / decoding is - QCBOR_MAX_ITEMS_IN_ARRAY (typically 65,536). - - Does not support encoding indefinite lengths (decoding is supported). - - Does not directly support some tagged types: decimal fractions, big floats - - Does not directly support labels in maps other than text strings and ints. - - Does not directly support int labels greater than INT64_MAX - - Epoch dates limited to INT64_MAX (+/- 292 billion years) - - Tags on labels are ignored during decoding - - This implementation is intended to run on 32 and 64-bit CPUs. Minor - modifications are needed for it to work on 16-bit CPUs. - - The public interface uses size_t for all lengths. Internally the - implementation uses 32-bit lengths by design to use less memory and - fit structures on the stack. This limits the encoded - CBOR it can work with to size UINT32_MAX (4GB) which should be - enough. - - This implementation assumes two's compliment integer - machines. Stdint.h also requires this. It of course would be easy to - fix this implementation for another integer representation, but all - modern machines seem to be two's compliment. - - */ - - -/** - The maximum number of items in a single array or map when encoding of decoding. -*/ -// -1 is because the value UINT16_MAX is used to track indefinite length arraysUINT16_MAX -#define QCBOR_MAX_ITEMS_IN_ARRAY (UINT16_MAX-1) - -/** - The maximum nesting of arrays and maps when encoding or decoding. The - error QCBOR_ERR_ARRAY_NESTING_TOO_DEEP will be returned on encoding - of decoding if it is exceeded -*/ -#define QCBOR_MAX_ARRAY_NESTING QCBOR_MAX_ARRAY_NESTING1 - -/** - The maximum number of tags that can be in QCBORTagListIn and passed to - QCBORDecode_SetCallerConfiguredTagList() - */ -#define QCBOR_MAX_CUSTOM_TAGS 16 - - -typedef enum { - /** The encode or decode completely correctly. */ - QCBOR_SUCCESS = 0, - - /** The buffer provided for the encoded output when doing encoding was - too small and the encoded output will not fit. Also, when the buffer - given to QCBORDecode_SetMemPool() is too small. */ - QCBOR_ERR_BUFFER_TOO_SMALL, - - /** During encoding or decoding, the array or map nesting was deeper than - this implementation can handle. Note that in the interest of code size - and memory use, this implementation has a hard limit on array nesting. The - limit is defined as the constant QCBOR_MAX_ARRAY_NESTING. */ - QCBOR_ERR_ARRAY_NESTING_TOO_DEEP, - - /** During decoding or encoding, the array or map had too many items in it. - This limit QCBOR_MAX_ITEMS_IN_ARRAY, typically 65,535. */ - QCBOR_ERR_ARRAY_TOO_LONG, - - /** During encoding, more arrays or maps were closed than opened. This is a - coding error on the part of the caller of the encoder. */ - QCBOR_ERR_TOO_MANY_CLOSES, - - /** During decoding, some CBOR construct was encountered that this decoder - doesn't support, primarily this is the reserved additional info values, - 28 through 30. */ - QCBOR_ERR_UNSUPPORTED, - - /** During decoding, hit the end of the given data to decode. For example, - a byte string of 100 bytes was expected, but the end of the input was - hit before finding those 100 bytes. Corrupted CBOR input will often - result in this error. */ - QCBOR_ERR_HIT_END, - - /** During encoding, the length of the encoded CBOR exceeded UINT32_MAX. - */ - QCBOR_ERR_BUFFER_TOO_LARGE, - - /** During decoding, an integer smaller than INT64_MIN was received (CBOR - can represent integers smaller than INT64_MIN, but C cannot). */ - QCBOR_ERR_INT_OVERFLOW, - - /** During decoding, the label for a map entry is bad. What causes this - error depends on the decoding mode. */ - QCBOR_ERR_MAP_LABEL_TYPE, - - /** During encoding or decoding, the number of array or map opens was not - matched by the number of closes. */ - QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN, - - /** During encoding, the simple value is not between CBOR_SIMPLEV_FALSE - and CBOR_SIMPLEV_UNDEF. */ - QCBOR_ERR_BAD_SIMPLE, - - /** During decoding, a date greater than +- 292 billion years from Jan 1 - 1970 encountered during parsing. */ - QCBOR_ERR_DATE_OVERFLOW, - - /** During decoding, the CBOR is not valid, primarily a simple type is encoded in - a prohibited way. */ - QCBOR_ERR_INVALID_CBOR, - - /** Optional tagging that doesn't make sense (an int is tagged as a - date string) or can't be handled. */ - QCBOR_ERR_BAD_OPT_TAG, - - /** Returned by QCBORDecode_Finish() if all the inputs bytes have not - been consumed. */ - QCBOR_ERR_EXTRA_BYTES, - - /** During encoding, QCBOREncode_Close() call with a different type than - is currently open. */ - QCBOR_ERR_CLOSE_MISMATCH, - - /** Unable to decode an indefinite length string because no string - allocator was configured. */ - QCBOR_ERR_NO_STRING_ALLOCATOR, - - /** One of the chunks in an indefinite length string is not of the type of - the string. */ - QCBOR_ERR_INDEFINITE_STRING_CHUNK, - - /** Error allocating space for a string, usually for an indefinite length - string. */ - QCBOR_ERR_STRING_ALLOCATE, - - /** During decoding, a break occurred outside an indefinite length item. */ - QCBOR_ERR_BAD_BREAK, - - /** During decoding, too many tags in the caller-configured tag list, or not - enough space in QCBORTagListOut. */ - QCBOR_ERR_TOO_MANY_TAGS, - - /** Returned by QCBORDecode_SetMemPool() when xx is too small. This should - never happen on a machine with 64-bit or smaller pointers. Fixing - it is probably by increasing QCBOR_DECODE_MIN_MEM_POOL_SIZE. */ - QCBOR_ERR_MEM_POOL_INTERNAL - -} QCBORError; - - -typedef enum { - /** See QCBORDecode_Init() */ - QCBOR_DECODE_MODE_NORMAL = 0, - /** See QCBORDecode_Init() */ - QCBOR_DECODE_MODE_MAP_STRINGS_ONLY = 1, - /** See QCBORDecode_Init() */ - QCBOR_DECODE_MODE_MAP_AS_ARRAY = 2 -} QCBORDecodeMode; - - - - - -/* Do not renumber these. Code depends on some of these values. */ -/** The type is unknown, unset or invalid */ -#define QCBOR_TYPE_NONE 0 -/** Type for an integer that decoded either between INT64_MIN and INT32_MIN or INT32_MAX and INT64_MAX; val.int64 */ -#define QCBOR_TYPE_INT64 2 -/** Type for an integer that decoded to a more than INT64_MAX and UINT64_MAX; val.uint64 */ -#define QCBOR_TYPE_UINT64 3 -/** Type for an array. The number of items in the array is in val.uCount. */ -#define QCBOR_TYPE_ARRAY 4 -/** Type for a map; number of items in map is in val.uCount */ -#define QCBOR_TYPE_MAP 5 -/** Type for a buffer full of bytes. Data is in val.string. */ -#define QCBOR_TYPE_BYTE_STRING 6 -/** Type for a UTF-8 string. It is not NULL terminated. Data is in val.string. */ -#define QCBOR_TYPE_TEXT_STRING 7 -/** Type for a positive big number. Data is in val.bignum, a pointer and a length. */ -#define QCBOR_TYPE_POSBIGNUM 9 -/** Type for a negative big number. Data is in val.bignum, a pointer and a length. */ -#define QCBOR_TYPE_NEGBIGNUM 10 -/** Type for RFC 3339 date string, possibly with time zone. Data is in val.dateString */ -#define QCBOR_TYPE_DATE_STRING 11 -/** Type for integer seconds since Jan 1970 + floating point fraction. Data is in val.epochDate */ -#define QCBOR_TYPE_DATE_EPOCH 12 -/** A simple type that this CBOR implementation doesn't know about; Type is in val.uSimple. */ -#define QCBOR_TYPE_UKNOWN_SIMPLE 13 -/** Type for the simple value false; nothing more; nothing in val union. */ -#define QCBOR_TYPE_FALSE 20 -/** Type for the simple value true; nothing more; nothing in val union. */ -#define QCBOR_TYPE_TRUE 21 -/** Type for the simple value null; nothing more; nothing in val union. */ -#define QCBOR_TYPE_NULL 22 -/** Type for the simple value undef; nothing more; nothing in val union. */ -#define QCBOR_TYPE_UNDEF 23 -/** Type for a floating point number. Data is in val.float. */ -#define QCBOR_TYPE_FLOAT 26 -/** Type for a double floating point number. Data is in val.double. */ -#define QCBOR_TYPE_DOUBLE 27 -/** For QCBOR_DECODE_MODE_MAP_AS_ARRAY decode mode, a map that is being traversed as an array. See QCBORDecode_Init() */ -#define QCBOR_TYPE_MAP_AS_ARRAY 32 - -#define QCBOR_TYPE_BREAK 31 // Used internally; never returned - -#define QCBOR_TYPE_OPTTAG 254 // Used internally; never returned - - - -/* - Approx Size of this: - 8 + 8 + 1 + 1 + 1 + (1 padding) + (4 padding on 64-bit machine) = 24 for first part (20 on a 32-bit machine) - 16 bytes for the val union - 16 bytes for label union - total = 56 bytes (52 bytes on 32-bit machine) - */ - -/** - QCBORItem holds the type, value and other info for a decoded item returned by GetNextItem(). - */ -typedef struct _QCBORItem { - uint8_t uDataType; /** Tells what element of the val union to use. One of QCBOR_TYPE_XXXX */ - uint8_t uNestingLevel; /** How deep the nesting from arrays and maps are. 0 is the top level with no arrays or maps entered */ - uint8_t uLabelType; /** Tells what element of the label union to use */ - uint8_t uDataAlloc; /** 1 if allocated with string allocator, 0 if not. See QCBORDecode_MakeMallocStringAllocator() */ - uint8_t uLabelAlloc; /** Like uDataAlloc, but for label */ - uint8_t uNextNestLevel; /** If not equal to uNestingLevel, this item closed out at least one map/array */ - - union { - int64_t int64; /** The value for uDataType QCBOR_TYPE_INT64 */ - uint64_t uint64; /** The value for uDataType QCBOR_TYPE_UINT64 */ - - UsefulBufC string; /** The value for uDataType QCBOR_TYPE_BYTE_STRING and QCBOR_TYPE_TEXT_STRING */ - uint16_t uCount; /** The "value" for uDataType QCBOR_TYPE_ARRAY or QCBOR_TYPE_MAP -- the number of items in the array or map - UINT16_MAX when decoding indefinite lengths maps and arrays. */ - double dfnum; /** The value for uDataType QCBOR_TYPE_DOUBLE */ - struct { - int64_t nSeconds; - double fSecondsFraction; - } epochDate; /** The value for uDataType QCBOR_TYPE_DATE_EPOCH */ - UsefulBufC dateString; /** The value for uDataType QCBOR_TYPE_DATE_STRING */ - UsefulBufC bigNum; /** The value for uDataType QCBOR_TYPE_BIGNUM */ - uint8_t uSimple; /** The integer value for unknown simple types */ - uint64_t uTagV; - - } val; /** The union holding the item's value. Select union member based on uDataType */ - - union { - UsefulBufC string; /** The label for uLabelType QCBOR_TYPE_BYTE_STRING and QCBOR_TYPE_TEXT_STRING */ - int64_t int64; /** The label for uLabelType for QCBOR_TYPE_INT64 */ - uint64_t uint64; /** The label for uLabelType for QCBOR_TYPE_UINT64 */ - } label; /** Union holding the different label types selected based on uLabelType */ - - uint64_t uTagBits; /** Bit indicating which tags (major type 6) on this item. */ - -} QCBORItem; - - -/** - This is a set of functions and pointer context (in object-oriented parlance, - an "object") used to allocate memory for coalescing the segments of an indefinite - length string into one. - - The fAllocate function works as an initial allocator and a reallocator to - expand the string for each new segment. When it is an initial allocator - pOldMem is NULL. - - The fFree function is called to clean up an individual allocation when an error occurs. - - The fDesctructor function is called when QCBORDecode_Finish is called. - - Any memory allocated with this will be marked by setting uDataAlloc - or uLabelAlloc in the QCBORItem structure so the caller knows they - have to free it. - - fAllocate is only ever called to increase the single most recent - allocation made, making implementation of a memory pool very simple. - - fFree is also only called on the single most recent allocation. - */ -typedef struct { - void *pAllocaterContext; - UsefulBuf (*fAllocate)(void *pAllocaterContext, void *pOldMem, size_t uNewSize); - void (*fFree)(void *pAllocaterContext, void *pMem); - void (*fDestructor)(void *pAllocaterContext); -} QCBORStringAllocator; - - -/** - This only matters if you use a string allocator - and and set it up with QCBORDecode_SetMemPool(). It is - the size of the overhead needed needed by - QCBORDecode_SetMemPool(). If you write your own - string allocator or use the separately available malloc - based string allocator, this size will not apply - */ -#define QCBOR_DECODE_MIN_MEM_POOL_SIZE 72 - - -/** - This is used to tell the decoder about tags that it should - record in uTagBits in QCBORItem beyond the built-in - tags. puTags points to an - array of uint64_t integers that are the tags. uNumTags - is the number of integers in the array. The maximum - size is QCBOR_MAX_CUSTOM_TAGS. See QCBORDecode_IsTagged() - and QCBORDecode_SetCallerAddedTagMap(). - */ -typedef struct { - uint8_t uNumTags; - const uint64_t *puTags; -} QCBORTagListIn; - - -/** - This is for QCBORDecode_GetNextWithTags() to be able to return the - full list of tags on an item. It not needed for most CBOR protocol - implementations. Its primary use is for pretty-printing CBOR or - protocol conversion to another format. - - On input, puTags points to a buffer to be filled in - and uNumAllocated is the number of uint64_t values - in the buffer. - - On output the buffer contains the tags for the item. - uNumUsed tells how many there are. - */ -typedef struct { - uint8_t uNumUsed; - uint8_t uNumAllocated; - uint64_t *puTags; -} QCBORTagListOut; - - -/** - QCBOREncodeContext is the data type that holds context for all the - encoding functions. It is less than 200 bytes, so it can go on - the stack. The contents are opaque, and the caller should not access - any internal items. A context may be re used serially as long as - it is re initialized. - */ -typedef struct _QCBOREncodeContext QCBOREncodeContext; - - -/** - Initialize the the encoder to prepare to encode some CBOR. - - @param[in,out] pCtx The encoder context to initialize. - @param[in] Storage The buffer into which this encoded result will be placed. - - Call this once at the start of an encoding of a CBOR structure. Then - call the various QCBOREncode_AddXXX() functions to add the data - items. Then call QCBOREncode_Finish(). - - The maximum output buffer is UINT32_MAX (4GB). This is not a practical - limit in any way and reduces the memory needed by the implementation. - The error QCBOR_ERR_BUFFER_TOO_LARGE will be returned by QCBOR_Finish() - if a larger buffer length is passed in. - - If this is called with pBuf as NULL and uBufLen a large value like - UINT32_MAX, all the QCBOREncode_AddXXXX() functions and - QCBORE_Encode_Finish() can still be called. No data will be encoded, - but the length of what would be encoded will be calculated. The - length of the encoded structure will be handed back in the call to - QCBOREncode_Finish(). You can then allocate a buffer of that size - and call all the encoding again, this time to fill in the buffer. - - A QCBORContext can be reused over and over as long as - QCBOREncode_Init() is called. - */ -void QCBOREncode_Init(QCBOREncodeContext *pCtx, UsefulBuf Storage); - - -/** - @brief Add a signed 64-bit integer to the encoded output. - - @param[in] pCtx The encoding context to add the integer to. - @param[in] nNum The integer to add. - - The integer will be encoded and added to the CBOR output. - - This function figures out the size and the sign and encodes in the - correct minimal CBOR. Specifically, it will select CBOR major type 0 or 1 - based on sign and will encode to 1, 2, 4 or 8 bytes depending on the - value of the integer. Values less than 24 effectively encode to one - byte because they are encoded in with the CBOR major type. This is - a neat and efficient characteristic of CBOR that can be taken - advantage of when designing CBOR-based protocols. If integers like - tags can be kept between -23 and 23 they will be encoded in one byte - including the major type. - - If you pass a smaller int, say an int16_t or a small value, say 100, - the encoding will still be CBOR's most compact that can represent the - value. For example, CBOR always encodes the value 0 as one byte, - 0x00. The representation as 0x00 includes identification of the type - as an integer too as the major type for an integer is 0. See RFC 7049 - Appendix A for more examples of CBOR encoding. This compact encoding - is also canonical CBOR as per section 3.9 in RFC 7049. - - There are no functions to add int16_t or int32_t because they are - not necessary because this always encodes to the smallest number - of bytes based on the value (If this code is running on a 32-bit - machine having a way to add 32-bit integers would reduce code size some). - - If the encoding context is in an error state, this will do - nothing. If an error occurs when adding this integer, the internal - error flag will be set, and the error will be returned when - QCBOREncode_Finish() is called. - - See also QCBOREncode_AddUInt64(). - */ -void QCBOREncode_AddInt64(QCBOREncodeContext *pCtx, int64_t nNum); - -static void QCBOREncode_AddInt64ToMap(QCBOREncodeContext *pCtx, const char *szLabel, int64_t uNum); - -static void QCBOREncode_AddInt64ToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, int64_t uNum); - - -/** - @brief Add an unsigned 64-bit integer to the encoded output. - - @param[in] pCtx The encoding context to add the integer to. - @param[in] uNum The integer to add. - - The integer will be encoded and added to the CBOR output. - - The only reason so use this function is for integers larger than - INT64_MAX and smaller than UINT64_MAX. Otherwise QCBOREncode_AddInt64() - will work fine. - - Error handling is the same as for QCBOREncode_AddInt64(). - */ -void QCBOREncode_AddUInt64(QCBOREncodeContext *pCtx, uint64_t uNum); - -static void QCBOREncode_AddUInt64ToMap(QCBOREncodeContext *pCtx, const char *szLabel, uint64_t uNum); - -static void QCBOREncode_AddUInt64ToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, uint64_t uNum); - - -/** - - @brief Add a UTF-8 text string to the encoded output - - @param[in] pCtx The context to initialize. - @param[in] Text Pointer and length of text to add. - - The text passed in must be unencoded UTF-8 according to RFC - 3629. There is no NULL termination. The text is added as CBOR - major type 3. - - If called with nBytesLen equal to 0, an empty string will be - added. When nBytesLen is 0, pBytes may be NULL. - - Note that the restriction of the buffer length to an uint32_t is - entirely intentional as this encoder is not capable of encoding - lengths greater. This limit to 4GB for a text string should not be a - problem. - - Error handling is the same as QCBOREncode_AddInt64(). - */ -static void QCBOREncode_AddText(QCBOREncodeContext *pCtx, UsefulBufC Text); - -static void QCBOREncode_AddTextToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Text); - -static void QCBOREncode_AddTextToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Text); - - -/** - @brief Add a UTF-8 text string to the encoded output - - @param[in] pCtx The context to initialize. - @param[in] szString Null-terminated text to add. - - This works the same as QCBOREncode_AddText(). - */ -static void QCBOREncode_AddSZString(QCBOREncodeContext *pCtx, const char *szString); - -static void QCBOREncode_AddSZStringToMap(QCBOREncodeContext *pCtx, const char *szLabel, const char *szString); - -static void QCBOREncode_AddSZStringToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, const char *szString); - - -/** - @brief Add a floating-point number to the encoded output - - @param[in] pCtx The encoding context to add the float to. - @param[in] dNum The double precision number to add. - - This outputs a floating-point number with CBOR major type 7. - - This will selectively encode the double-precision floating point - number as either double-precision, single-precision or - half-precision. It will always encode infinity, NaN and 0 has half - precision. If no precision will be lost in the conversion to - half-precision then it will be converted and encoded. If not and no - precision will be lost in conversion to single-precision, then it - will be converted and encoded. If not, then no conversion is - performed, and it encoded as a double. - - Half-precision floating point numbers take up 2 bytes, half that of - single-precision, one quarter of double-precision - - This automatically reduces the size of encoded messages a lot, maybe - even by four if most of values are 0, infinity or NaN. - - On decode, these will always be returned as a double. - - Error handling is the same as QCBOREncode_AddInt64(). - */ -void QCBOREncode_AddDouble(QCBOREncodeContext *pCtx, double dNum); - -static void QCBOREncode_AddDoubleToMap(QCBOREncodeContext *pCtx, const char *szLabel, double dNum); - -static void QCBOREncode_AddDoubleToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, double dNum); - - -/** - @brief[in] Add an optional tag - - @param[in] pCtx The encoding context to add the integer to. - @param[in] uTag The tag to add - - This outputs a CBOR major type 6 optional tag. - - The tag is applied to the next data item added to the encoded - output. That data item that is to be tagged can be of any major - CBOR type. Any number of tags can be added to a data item by calling - this multiple times before the data item is added. - - For many of the common standard tags a function to encode - data using it already exists and this is not needed. For example, - QCBOREncode_AddDateEpoch() already exists to output - integers representing dates with the right tag. -*/ -void QCBOREncode_AddTag(QCBOREncodeContext *pCtx,uint64_t uTag); - - -/** - @brief Add an epoch-based date - - @param[in] pCtx The encoding context to add the simple value to. - @param[in] date Number of seconds since 1970-01-01T00:00Z in UTC time. - - As per RFC 7049 this is similar to UNIX/Linux/POSIX dates. This is - the most compact way to specify a date and time in CBOR. Note that this - is always UTC and does not include the time zone. Use - QCBOREncode_AddDateString() if you want to include the time zone. - - The integer encoding rules apply here so the date will be encoded in a - minimal number of 1, 2 4 or 8 bytes. Until about the year 2106 these - dates should encode in 6 bytes -- one byte for the tag, one byte for the type - and 4 bytes for the integer. - - If you care about leap-seconds and that level of accuracy, make sure the - system you are running this code on does it correctly. This code just takes - the value passed in. - - This implementation cannot encode fractional seconds using float or double - even though that is allowed by CBOR, but you can encode them if you - want to by calling QCBOREncode_AddDouble() - with the right parameters. - - Error handling is the same as QCBOREncode_AddInt64(). - */ -static void QCBOREncode_AddDateEpoch(QCBOREncodeContext *pCtx, int64_t date); - -static void QCBOREncode_AddDateEpochToMap(QCBOREncodeContext *pCtx, const char *szLabel, int64_t date); - -static void QCBOREncode_AddDateEpochToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, int64_t date); - - -/** - @brief Add a byte string to the encoded output. - - @param[in] pCtx The context to initialize. - @param[in] Bytes Pointer and length of the input data. - - Simply adds the bytes to the encoded output as CBOR major type 2. - - If called with Bytes.len equal to 0, an empty string will be - added. When Bytes.len is 0, Bytes.ptr may be NULL. - - Error handling is the same as QCBOREncode_AddInt64(). - */ -static void QCBOREncode_AddBytes(QCBOREncodeContext *pCtx, UsefulBufC Bytes); - -static void QCBOREncode_AddBytesToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Bytes); - -static void QCBOREncode_AddBytesToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Bytes); - - - -/** - @brief Add a binary UUID to the encoded output. - - @param[in] pCtx The context to initialize. - @param[in] Bytes Pointer and length of the binary UUID. - - A binary UUID as defined in RFC 4122 is added to the ouput. - - It is output as CBOR major type 2, a binary string, with - optional tag 36 indicating the binary string is a UUID. - */ -static void QCBOREncode_AddBinaryUUID(QCBOREncodeContext *pCtx, UsefulBufC Bytes); - -static void QCBOREncode_AddBinaryUUIDToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Bytes); - -static void QCBOREncode_AddBinaryUUIDToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Bytes); - - -/** - @brief Add a positive big number to the encoded output. - - @param[in] pCtx The context to initialize. - @param[in] Bytes Pointer and length of the big number. - - Big numbers are integers larger than 64-bits. Their format - is described in RFC 7049. - - It is output as CBOR major type 2, a binary string, with - optional tag 2 indicating the binary string is a positive big - number. - - Often big numbers are used to represent cryptographic keys, - however, COSE which defines representations for keys chose not - to use this particular type. - */ -static void QCBOREncode_AddPositiveBignum(QCBOREncodeContext *pCtx, UsefulBufC Bytes); - -static void QCBOREncode_AddPositiveBignumToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Bytes); - -static void QCBOREncode_AddPositiveBignumToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Bytes); - - -/** - @brief Add a negative big number to the encoded output. - - @param[in] pCtx The context to initialize. - @param[in] Bytes Pointer and length of the big number. - - Big numbers are integers larger than 64-bits. Their format - is described in RFC 7049. - - It is output as CBOR major type 2, a binary string, with - optional tag 2 indicating the binary string is a negative big - number. - - Often big numbers are used to represent cryptographic keys, - however, COSE which defines representations for keys chose not - to use this particular type. - */ -static void QCBOREncode_AddNegativeBignum(QCBOREncodeContext *pCtx, UsefulBufC Bytes); - -static void QCBOREncode_AddNegativeBignumToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Bytes); - -static void QCBOREncode_AddNegativeBignumToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Bytes); - - -/** - @brief Add a text URI to the encoded output. - - @param[in] pCtx The context to initialize. - @param[in] URI Pointer and length of the URI. - - The format of URI is RFC 3986. - - It is output as CBOR major type 3, a text string, with - optional tag 32 indicating the text string is a URI. - */ -static void QCBOREncode_AddURI(QCBOREncodeContext *pCtx, UsefulBufC URI); - -static void QCBOREncode_AddURIToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC URI); - -static void QCBOREncode_AddURIToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC URI); - - -/** - @brief Add base 64-encoded text to encoded output. - - @param[in] pCtx The context to initialize. - @param[in] B64Text Pointer and length of the base-64 encoded text. - - The text content is base 64 encoded data per RFC 4648. - - It is output as CBOR major type 3, a text string, with - optional tag 34 indicating the text string is a URI. - */ -static void QCBOREncode_AddB64Text(QCBOREncodeContext *pCtx, UsefulBufC B64Text); - -static void QCBOREncode_AddB64TextToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC B64Text); - -static void QCBOREncode_AddB64TextToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC B64Text); - - -/** - @brief Add base 64URL -encoded URL to encoded output. - - @param[in] pCtx The context to initialize. - @param[in] B64Text Pointer and length of the base-64 encoded text. - - The text content is base 64 URL format encoded text as per RFC 4648. - - It is output as CBOR major type 3, a text string, with - optional tag 33 indicating the text string is a URI. - */ -static void QCBOREncode_AddB64URLText(QCBOREncodeContext *pCtx, UsefulBufC B64Text); - -static void QCBOREncode_AddB64URLTextToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC B64Text); - -static void QCBOREncode_AddB64URLTextToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC B64Text); - - -/** - @brief Add Perl Compatible Regular Expression - - @param[in] pCtx The context to initialize. - @param[in] Regex Pointer and length of the regular expression. - - The text content is Perl Compatible Regular - Expressions (PCRE) / JavaScript syntax [ECMA262]. - - It is output as CBOR major type 3, a text string, with - optional tag 35 indicating the text string is a regular expression. - */ -static void QCBOREncode_AddRegex(QCBOREncodeContext *pCtx, UsefulBufC Regex); - -static void QCBOREncode_AddRegexToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Regex); - -static void QCBOREncode_AddRegexToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Regex); - - -/** - @brief MIME encoded text to the encoded output. - - @param[in] pCtx The context to initialize. - @param[in] MIMEData Pointer and length of the regular expression. - - The text content is in MIME format per RFC 2045 including the headers. - - It is output as CBOR major type 3, a text string, with - optional tag 36 indicating the text string is MIME data. - */ -static void QCBOREncode_AddMIMEData(QCBOREncodeContext *pCtx, UsefulBufC MIMEData); - -static void QCBOREncode_AddMIMEDataToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC MIMEData); - -static void QCBOREncode_AddMIMEDataToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC MIMEData); - - -/** - @brief Add an RFC 3339 date string - - @param[in] pCtx The encoding context to add the simple value to. - @param[in] szDate Null-terminated string with date to add - - The string szDate should be in the form of RFC 3339 as defined by section - 3.3 in RFC 4287. This is as described in section 2.4.1 in RFC 7049. - - Note that this function doesn't validate the format of the date string - at all. If you add an incorrect format date string, the generated - CBOR will be incorrect and the receiver may not be able to handle it. - - Error handling is the same as QCBOREncode_AddInt64(). - */ -static void QCBOREncode_AddDateString(QCBOREncodeContext *pCtx, const char *szDate); - -static void QCBOREncode_AddDateStringToMap(QCBOREncodeContext *pCtx, const char *szLabel, const char *szDate); - -static void QCBOREncode_AddDateStringToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, const char *szDate); - - -/** - @brief Add a standard boolean. - - @param[in] pCtx The encoding context to add the simple value to. - @param[in] b true or false from stdbool. Anything will result in an error. - - Adds a boolean value as CBOR major type 7. - - Error handling is the same as QCBOREncode_AddInt64(). - */ -static void QCBOREncode_AddBool(QCBOREncodeContext *pCtx, bool b); - -static void QCBOREncode_AddBoolToMap(QCBOREncodeContext *pCtx, const char *szLabel, bool b); - -static void QCBOREncode_AddBoolToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, bool b); - - - -/** - @brief Add a NULL to the encoded output. - - @param[in] pCtx The encoding context to add the simple value to. - - Adds the NULL value as CBOR major type 7. - - This NULL doesn't have any special meaning in CBOR such as a terminating - value for a string or an empty value. - - Error handling is the same as QCBOREncode_AddInt64(). - */ -static void QCBOREncode_AddNULL(QCBOREncodeContext *pCtx); - -static void QCBOREncode_AddNULLToMap(QCBOREncodeContext *pCtx, const char *szLabel); - -static void QCBOREncode_AddNULLToMapN(QCBOREncodeContext *pCtx, int64_t nLabel); - - -/** - @brief Add an "undef" to the encoded output. - - @param[in] pCtx The encoding context to add the simple value to. - - Adds the undef value as CBOR major type 7. - - Note that this value will not translate to JSON. - - This Undef doesn't have any special meaning in CBOR such as a terminating - value for a string or an empty value. - - Error handling is the same as QCBOREncode_AddInt64(). - */ -static void QCBOREncode_AddUndef(QCBOREncodeContext *pCtx); - -static void QCBOREncode_AddUndefToMap(QCBOREncodeContext *pCtx, const char *szLabel); - -static void QCBOREncode_AddUndefToMapN(QCBOREncodeContext *pCtx, int64_t nLabel); - - -/** - @brief Indicates that the next items added are in an array. - - @param[in] pCtx The encoding context to open the array in. - - Arrays are the basic CBOR aggregate or structure type. Call this - function to start or open an array. Then call the various AddXXX - functions to add the items that go into the array. Then call - QCBOREncode_CloseArray() when all items have been added. The data - items in the array can be of any type and can be of mixed types. - - Nesting of arrays and maps is allowed and supported just by calling - QCBOREncode_OpenArray() again before calling CloseArray. While CBOR - has no limit on nesting, this implementation does in order to keep it - smaller and simpler. The limit is QCBOR_MAX_ARRAY_NESTING. This is - the max number of times this can be called without calling - QCBOREncode_CloseArray(). QCBOREncode_Finish() will return - QCBOR_ERR_ARRAY_NESTING_TOO_DEEP when it is called as this function - just sets an error state and returns no value when this occurs. - - If you try to add more than QCBOR_MAX_ITEMS_IN_ARRAY items to a - single array or map, QCBOR_ERR_ARRAY_TOO_LONG will be returned when - QCBOREncode_Finish() is called. - - An array itself must have a label if it is being added to a map. - Note that array elements do not have labels (but map elements do). - - An array itself may be tagged. - */ -static void QCBOREncode_OpenArray(QCBOREncodeContext *pCtx); - -static void QCBOREncode_OpenArrayInMap(QCBOREncodeContext *pCtx, const char *szLabel); - -static void QCBOREncode_OpenArrayInMapN(QCBOREncodeContext *pCtx, int64_t nLabel); - - -/** - @brief Close an open array. - - @param[in] pCtx The context to add to. - - The closes an array opened by QCBOREncode_OpenArray(). It reduces - nesting level by one. All arrays (and maps) must be closed before - calling QCBOREncode_Finish(). - - When an error occurs as a result of this call, the encoder records - the error and enters the error state. The error will be returned when - QCBOREncode_Finish() is called. - - If this has been called more times than QCBOREncode_OpenArray(), then - QCBOR_ERR_TOO_MANY_CLOSES will be returned when QCBOREncode_Finish() - is called. - - If this is called and it is not an array that is currently open, - QCBOR_ERR_CLOSE_MISMATCH will be returned when QCBOREncode_Finish() - is called. - */ -static void QCBOREncode_CloseArray(QCBOREncodeContext *pCtx); - - -/** - @brief Indicates that the next items added are in a map. - - @param[in] pCtx The context to add to. - - See QCBOREncode_OpenArray() for more information, particularly error - handling. - - CBOR maps are an aggregate type where each item in the map consists - of a label and a value. They are similar to JSON objects. - - The value can be any CBOR type including another map. - - The label can also be any CBOR type, but in practice they are - typically, integers as this gives the most compact output. They might - also be text strings which gives readability and translation to JSON. - - Every QCBOREncode_AddXXX() call has once version that is "InMap" for - adding items to maps with string labels and on that is "InMapN" that - is for adding with integer labels. - - RFC 7049 uses the term "key" instead of "label". - - If you wish to use map labels that are neither integer labels or - text strings, then just call the QCBOREncode_AddXXX() function - explicitly to add the label. Then call it again to add the value. - - See the RFC7049 for a lot more information on creating maps. - */ -static void QCBOREncode_OpenMap(QCBOREncodeContext *pCtx); - -static void QCBOREncode_OpenMapInMap(QCBOREncodeContext *pCtx, const char *szLabel); - -static void QCBOREncode_OpenMapInMapN(QCBOREncodeContext *pCtx, int64_t nLabel); - - - -/** - @brief Close an open map. - - @param[in] pCtx The context to add to. - - The closes a map opened by QCBOREncode_OpenMap(). It reduces nesting - level by one. - - When an error occurs as a result of this call, the encoder records - the error and enters the error state. The error will be returned when - QCBOREncode_Finish() is called. - - If this has been called more times than QCBOREncode_OpenMap(), - then QCBOR_ERR_TOO_MANY_CLOSES will be returned when - QCBOREncode_Finish() is called. - - If this is called and it is not a map that is currently - open, QCBOR_ERR_CLOSE_MISMATCH will be returned when QCBOREncode_Finish() - is called. - */ -static void QCBOREncode_CloseMap(QCBOREncodeContext *pCtx); - - -/** - @brief Indicate start of encoded CBOR to be wrapped in a bstr. - - @param[in] pCtx The context to add to. - - All added encoded items between this call and a call to - QCBOREncode_CloseBstrWrap() will be wrapped in a bstr. They will - appear in the final output as a byte string. That byte string will - contain encoded CBOR. - - The typical use case is for encoded CBOR that is to be - cryptographically hashed, as part of a COSE (RFC 8152) - implementation. This avoids having to encode the items first in one - buffer (e.g., the COSE payload) and then add that buffer as a bstr to - another encoding (e.g. the COSE to-be-signed bytes, the - Sig_structure) potentially saving a lot of memory. - - When constructing cryptographically signed CBOR objects, maps or - arrays, they typically are encoded normally and then wrapped as a - byte string. The COSE standard for example does this. The wrapping is - simply treating the encoded CBOR map as a byte string. - - The stated purpose of this wrapping is to prevent code relaying the - signed data but not verifying it from tampering with the signed data - thus making the signature unverifiable. It is also quite beneficial - for the signature verification code. Standard CBOR parsers usually do - not give access to partially parsed CBOR as would be need to check - the signature of some CBOR. With this wrapping, standard CBOR parsers - can be used to get to all the data needed for a signature - verification. - */ -static void QCBOREncode_BstrWrap(QCBOREncodeContext *pCtx); - -static void QCBOREncode_BstrWrapInMap(QCBOREncodeContext *pCtx, const char *szLabel); - -static void QCBOREncode_BstrWrapInMapN(QCBOREncodeContext *pCtx, int64_t nLabel); - - -/** - @brief Close a wrapping bstr. - - @param[in] pCtx The context to add to. - @param[out] pWrappedCBOR UsefulBufC containing wrapped bytes - - The closes a wrapping bstr opened by QCBOREncode_BstrWrap(). It reduces - nesting level by one. - - A pointer and length of the enclosed encoded CBOR is returned in - *pWrappedCBOR if it is not NULL. The main purpose of this is so this - data can be hashed (e.g., with SHA-256) as part of a COSE (RFC 8152) - implementation. **WARNING**, this pointer and length should be used - right away before any other calls to QCBOREncode_xxxx() as they will - move data around and the pointer and length will no longer be to the - correct encoded CBOR. - - When an error occurs as a result of this call, the encoder records - the error and enters the error state. The error will be returned when - QCBOREncode_Finish() is called. - - If this has been called more times then QCBOREncode_BstrWrap(), - then QCBOR_ERR_TOO_MANY_CLOSES will be returned when - QCBOREncode_Finish() is called. - - If this is called and it is not a wrapping bstr that is currently - open, QCBOR_ERR_CLOSE_MISMATCH will be returned when QCBOREncode_Finish() - is called. - */ -static void QCBOREncode_CloseBstrWrap(QCBOREncodeContext *pCtx, UsefulBufC *pWrappedCBOR); - - -/** - @brief Add some already-encoded CBOR bytes. - - @param[in] pCtx The context to add to. - @param[in] Encoded The already-encoded CBOR to add to the context. - - The encoded CBOR being added must be fully conforming CBOR. It must - be complete with no arrays or maps that are incomplete. While this - encoder doesn't ever produce indefinite lengths, it is OK for the - raw CBOR added here to have indefinite lengths. - - The raw CBOR added here is not checked in anyway. If it is not - conforming or has open arrays or such, the final encoded CBOR - will probably be wrong or not what was intended. - - If the encoded CBOR being added here contains multiple items, they - must be enclosed in a map or array. At the top level the raw - CBOR must be a single data item. - */ -static void QCBOREncode_AddEncoded(QCBOREncodeContext *pCtx, UsefulBufC Encoded); - -static void QCBOREncode_AddEncodedToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Encoded); - -static void QCBOREncode_AddEncodedToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Encoded); - - -/** - @brief Get the encoded result. - - @param[in] pCtx The context to finish encoding with. - @param[out] pEncodedCBOR Pointer and length of encoded CBOR. - - @return - One of the CBOR error codes. - - If this returns success QCBOR_SUCCESS the encoding was a success and - the return length is correct and complete. - - If no buffer was passed to QCBOR_Init(), then only the length and - number of items was computed. The length is in - pEncodedCBOR->Bytes.len. pEncodedCBOR->Bytes.ptr is NULL. - - If a buffer was passed, then pEncodedCBOR->Bytes.ptr is the same as - the buffer passed to QCBOR_Init() and contains the encoded CBOR - and the length is filled in. - - If an error is returned, the buffer may have partially encoded - incorrect CBOR in it and it should not be used. Likewise, the length - may be incorrect and should not be used. - - Note that the error could have occurred in one of the many - QCBOR_AddXXX calls long before QCBOREncode_Finish() was called. This - error handling approach reduces the CBOR implementation size, but makes - debugging a problem a little more difficult. - */ -QCBORError QCBOREncode_Finish(QCBOREncodeContext *pCtx, UsefulBufC *pEncodedCBOR); - - -/** - @brief Get the encoded CBOR and error status. - - @param[in] pCtx The context to finish encoding with. - @param[out] uEncodedLen The length of the encoded or potentially encoded CBOR in bytes. - - @return - One of the CBOR error codes. - - If this returns success QCBOR_SUCCESS the encoding was a success and - the return length is correct and complete. - - If no buffer was passed to QCBOR_Init(), then only the length was - computed. If a buffer was passed, then the encoded CBOR is in the - buffer. - - If an error is returned, the buffer may have partially encoded - incorrect CBOR in it and it should not be used. Likewise, the length - may be incorrect and should not be used. - - Note that the error could have occurred in one of the many - QCBOR_AddXXX calls long before QCBOREncode_Finish() was called. This - error handling reduces the CBOR implementation size, but makes - debugging harder. - */ -QCBORError QCBOREncode_FinishGetSize(QCBOREncodeContext *pCtx, size_t *uEncodedLen); - - - - - - -/** - QCBORDecodeContext is the data type that holds context decoding the - data items for some received CBOR. It is about 100 bytes, so it can go - on the stack. The contents are opaque, and the caller should not - access any internal items. A context may be re used serially as long - as it is re initialized. - */ -typedef struct _QCBORDecodeContext QCBORDecodeContext; - - -/** - Initialize the CBOR decoder context. - - @param[in] pCtx The context to initialize. - @param[in] EncodedCBOR The buffer with CBOR encoded bytes to be decoded. - @param[in] nMode One of QCBOR_DECODE_MODE_xxx - - Initialize context for a pre-order travesal of the encoded CBOR tree. - - Most CBOR decoding can be completed by calling this function to start - and QCBORDecode_GetNext() in a loop. - - If indefinite length strings are to be decoded, then - QCBORDecode_SetMemPool() or QCBORDecode_SetUpAllocator() must be - called to set up a string allocator. - - If tags other than built-in tags are to be recognized, then - QCBORDecode_SetCallerAddedTagMap() must be called. The built-in tags - are those for which a macro of the form CBOR_TAG_XXX is defined. - - Three decoding modes are supported. In normal mode, - QCBOR_DECODE_MODE_NORMAL, maps are decoded and strings and ints are - accepted as map labels. If a label is other than these, the error - QCBOR_ERR_MAP_LABEL_TYPE is returned by QCBORDecode_GetNext(). - - In strings-only mode, QCBOR_DECODE_MODE_MAP_STRINGS_ONLY, only text - strings are accepted for map labels. This lines up with CBOR that - converts to JSON. The error QCBOR_ERR_MAP_LABEL_TYPE is returned by - QCBORDecode_GetNext() if anything but a text string label is - encountered. - - In QCBOR_DECODE_MODE_MAP_AS_ARRAY maps are treated as special arrays. - They will be return with special uDataType QCBOR_TYPE_MAP_AS_ARRAY - and uCount, the number of items, will be double what it would be - for a normal map because the labels are also counted. This mode - is useful for decoding CBOR that has labels that are not - integers or text strings, but the caller must manage much of - the map decoding. - */ -void QCBORDecode_Init(QCBORDecodeContext *pCtx, UsefulBufC EncodedCBOR, QCBORDecodeMode nMode); - - -/** - @brief Set up the MemPool string allocator for indefinite length strings. - - @param[in] pCtx The decode context. - @param[in] MemPool The pointer and length of the memory pool. - @param[in] bAllStrings true means to put even definite length strings in the pool. - - @return error if the MemPool was less than QCBOR_DECODE_MIN_MEM_POOL_SIZE. - - Indefinite length strings (text and byte) cannot be decoded unless - there is a string allocator configured. MemPool is a simple built-in - string allocator that allocates bytes from a memory pool handed to it - by calling this function. The memory pool is just a pointer and - length for some block of memory that is to be used for string - allocation. It can come from the stack, heap or other. - - The memory pool must be QCBOR_DECODE_MIN_MEM_POOL_SIZE plus space for - all the strings allocated. There is no overhead per string allocated - - This memory pool is used for all indefinite length strings that are - text strings or byte strings, including strings used as labels. - - The pointers to strings in QCBORItem will point into the memory pool set - here. They do not need to be individually freed. Just discard the buffer - when they are no longer needed. - - If bAllStrings is set, then the size will be the overhead plus the - space to hold **all** strings, definite and indefinite length, value - or label. The advantage of this is that after the decode is complete, - the original memory holding the encoded CBOR does not need to remain - valid. - - If this function is never called because there is no need to support - indefinite length strings, the MemPool implementation should be - dead-stripped by the loader and not add to code size. - */ -QCBORError QCBORDecode_SetMemPool(QCBORDecodeContext *pCtx, UsefulBuf MemPool, bool bAllStrings); - - -/** - @brief Sets up a custom string allocator for indefinite length strings - - @param[in] pCtx The decoder context to set up an allocator for - @param[in] pAllocator The string allocator "object" - - See QCBORStringAllocator for the requirements of the string allocator. - - Typically, this is used if the simple MemPool allocator isn't desired. - - A malloc based string allocator can be obtained by calling - QCBOR_DMalloc(). This function is supply separately from qcbor - to keep qcbor smaller and neater. It is in a separate - GitHub repository. - - You can also write your own allocator. Create the allocate, free, - and destroy functions and put pointers to them in a QCBORStringAllocator. - */ -void QCBORDecode_SetUpAllocator(QCBORDecodeContext *pCtx, const QCBORStringAllocator *pAllocator, bool bAllStrings); - - -/** - @brief Configure list of caller selected tags to be recognized - - @param[in] pCtx The decode context. - @param[out] pTagList Structure holding the list of tags to configure - - This is used to tell the decoder about tags beyond those that are - built-in that should be recognized. The built-in tags are those - with macros of the form CBOR_TAG_XXX. - - See description of QCBORTagListIn. - */ -void QCBORDecode_SetCallerConfiguredTagList(QCBORDecodeContext *pCtx, const QCBORTagListIn *pTagList); - - -/** - @brief Gets the next item (integer, byte string, array...) in pre order traversal of CBOR tree - - @param[in] pCtx The decoder context. - @param[out] pDecodedItem Holds the CBOR item just decoded. - - @return 0 or error. All errors except QCBOR_ERR_TOO_MANY_TAGS - and QCBOR_ERR_STRING_ALLOCATE indicate that the CBOR input - could not be decoded. In most cases - this is because the CBOR is invalid. In a few cases - (QCBOR_ERR_ARRAY_NESTING_TOO_DEEP, QCBOR_ERR_INT_OVERFLOW, - QCBOR_ERR_DATE_OVERFLOW) it is because the CBOR is beyond - the limits of what this implementation can handle. - QCBOR_ERR_NO_STRING_ALLOCATOR indicates CBOR that cannot - be handled unless a string allocator is configured. - QCBOR_ERR_MAP_LABEL_TYPE is in a way a limitation of - this implementation, but can be avoided by decoding - in QCBOR_DECODE_MODE_MAP_AS_ARRAY mode. - - pDecodedItem is filled in with the value parsed. Generally, the - following data is returned in the structure. - - - The data type in uDataType which indicates which member of the val - union the data is in. This decoder figures out the type based on the - CBOR major type, the CBOR "additionalInfo", the CBOR optional tags - and the value of the integer. - - - The value of the item, which might be an integer, a pointer and a - length, the count of items in an array, a floating-point number or - other. - - - The nesting level for maps and arrays. - - - The label for an item in a map, which may be a text or byte string or an integer. - - - The CBOR optional tag or tags. - - See documentation on in the data type QCBORItem for all the details - on what is returned. - - This function also handles arrays and maps. When first encountered a - QCBORItem will be returned with major type CBOR_MAJOR_TYPE_ARRAY or - CBOR_MAJOR_TYPE_ARRAY_MAP. QCBORItem.val.uCount will indicate the number - of Items in the array or map. Typically, an implementation will call - QCBORDecode_GetNext() in a for loop to fetch them all. When decoding - indefinite length maps and arrays, QCBORItem.val.uCount is UINT16_MAX - and uNextNestLevel must be used to know when the end of a map - or array is reached. - - Nesting level 0 is the outside top-most nesting level. For example, in - a CBOR structure with two items, an integer and a byte string only, - both would be at nesting level 0. A CBOR structure with an array - open, an integer and a byte string, would have the integer and byte - string as nesting level 1. - - Here is an example of how the nesting level is reported with no arrays - or maps at all - - @verbatim - CBOR Structure Nesting Level - Integer 0 - Byte String 0 - @endverbatim - - Here is an example of how the nesting level is reported with an a simple - array and some top-level items. - - @verbatim - Integer 0 - Array (with 2 items) 0 - Byte String 1 - Byte string 1 - Integer 0 - @endverbatim - - - Here's a more complex example - @verbatim - - Map with 2 items 0 - Text string 1 - Array with 3 integers 1 - integer 2 - integer 2 - integer 2 - text string 1 - byte string 1 - @endverbatim - - In QCBORItem, uNextNestLevel is the nesting level for the next call - to QCBORDecode_GetNext(). It indicates if any maps or arrays were closed - out during the processing of the just-fecthed QCBORItem. This processing - includes a look-ahead for any breaks that close out indefinite length - arrays or maps. This value is needed to be able to understand the - hierarchical structure. If uNextNestLevel is not equal to uNestLevel - the end of the current map or array has been encountered. This - works the same for both definite and indefinite length arrays. - - Most uses of this decoder will not need to do anything extra for - tag handling. The built-in tags, those with a macro of the form - CBOR_TAG_XXXX, will be enough. - - If tags beyond built-in tags are to be recognized, they must be - configured by calling QCBORDecode_SetCallerConfiguredTags(). If - a tag is not recognized it is silently ignored. - - Several tagged types are automatically recognized and decoded and - returned in their decoded form. - - To find out if a QCBORItem was tagged with a particular tag - call QCBORDecode_IsTagged(). This works only for built-in - tags and caller-configured tags. - - To get the full list of tags on an Item without having to - pre-configure any predetermined list of tags use - QCBORDecode_GetNextWithTags(). - */ -QCBORError QCBORDecode_GetNext(QCBORDecodeContext *pCtx, QCBORItem *pDecodedItem); - - -/** - @brief Gets the next item including full list of tags for item - - @param[in] pCtx The decoder context. - @param[out] pDecodedItem Holds the CBOR item just decoded. - @param[in,out] pTagList On input array to put tags in; on output the tags on this item. - - @return 0 or error. - - This works the same as QCBORDecode_GetNext() except that it also returns - the full list of tags for the data item. This function should only - be needed when parsing CBOR to print it out or convert it to some other - format. It should not be needed in an actual CBOR protocol implementation. - - Tags will be returned here whether or not they are in the built-in or - caller-configured tag lists. - - CBOR has no upper bound of limit on the number of tags that can be - associated with a data item. In practice the number of tags on an item - will usually be small, perhaps less than five. This will return an error - if the array in pTagList is too small to hold all the tags for an item. - - (This function is separate from QCBORDecode_GetNext() so as to not have to - make QCBORItem large enough to be able to hold a full list of tags. Even a list of - five tags would nearly double its size because tags can be a uint64_t). - */ -QCBORError QCBORDecode_GetNextWithTags(QCBORDecodeContext *pCtx, QCBORItem *pDecodedItem, QCBORTagListOut *pTagList); - - -/** - @brief Determine if a CBOR item was tagged with a particular tag - - @param[in] pCtx The decoder context. - @param[in] pItem The CBOR item to check - @param[in] uTag The tag to check - - @return 1 if it was tagged, 0 if not - - QCBORDecode_GetNext() processes tags by looking them up - in two lists and setting a bit corresponding to the tag - in uTagBits in the QCBORItem. To find out if a - QCBORItem was tagged with a particular tag, call - this function. It handles the mapping between - the two lists of tags and the bits set for it. - - The first tag list is the built-in tags, those - with a macro of the form CBOR_TAG_XXX in this - header file. There are up to 48 of these, - corresponding to the lower 48 tag bits. - - The other optional tag list is the ones - the caller configured using QCBORDecode_SetCallerConfiguredTagList() - There are QCBOR_MAX_CUSTOM_TAGS (16) of these corresponding to the - upper 16 tag bits. - - See also QCBORDecode_GetTags() and QCBORDecode_GetNextWithTags(). - */ -int QCBORDecode_IsTagged(QCBORDecodeContext *pCtx, const QCBORItem *pItem, uint64_t uTag); - - -/** - Check whether all the bytes have been decoded and maps and arrays closed. - - @param[in] pCtx The context to check - - @return QCBOR_SUCCESS or error - - This tells you if all the bytes given to QCBORDecode_Init() have - been consumed and whether all maps and arrays were closed. - The decode is considered to be incorrect or incomplete if not - and an error will be returned. - */ -QCBORError QCBORDecode_Finish(QCBORDecodeContext *pCtx); - - - - -/** - Convert int64_t to smaller int's safely - - @param [in] src An int64_t - @param [out] dest A smaller sized int to convert to - - @return 0 on success -1 if not - - When decoding an integer, the CBOR decoder will return the value as an - int64_t unless the integer is in the range of INT64_MAX and - UINT64_MAX. That is, unless the value is so large that it can only be - represented as a uint64_t, it will be an int64_t. - - CBOR itself doesn't size the individual integers it carries at - all. The only limits it puts on the major integer types is that they - are 8 bytes or less in length. Then encoders like this one use the - smallest number of 1, 2, 4 or 8 bytes to represent the integer based - on its value. There is thus no notion that one data item in CBOR is - an 1 byte integer and another is a 4 byte integer. - - The interface to this CBOR encoder only uses 64-bit integers. Some - CBOR protocols or implementations of CBOR protocols may not want to - work with something smaller than a 64-bit integer. Perhaps an array - of 1000 integers needs to be sent and none has a value larger than - 50,000 and are represented as uint16_t. - - The sending / encoding side is easy. Integers are temporarily widened - to 64-bits as a parameter passing through QCBOREncode_AddInt64() and - encoded in the smallest way possible for their value, possibly in - less than an uint16_t. - - On the decoding side the integers will be returned at int64_t even if - they are small and were represented by only 1 or 2 bytes in the - encoded CBOR. The functions here will convert integers to a small - representation with an overflow check. - - (The decoder could have support 8 different integer types and - represented the integer with the smallest type automatically, but - this would have made the decoder more complex and code calling the - decoder more complex in most use cases. In most use cases on 64-bit - machines it is no burden to carry around even small integers as - 64-bit values). - */ -static inline int QCBOR_Int64ToInt32(int64_t src, int32_t *dest) -{ - if(src > INT32_MAX || src < INT32_MIN) { - return -1; - } else { - *dest = (int32_t) src; - } - return 0; -} - -static inline int QCBOR_Int64ToInt16(int64_t src, int16_t *dest) -{ - if(src > INT16_MAX || src < INT16_MIN) { - return -1; - } else { - *dest = (int16_t) src; - } - return 0; -} - -static inline int QCBOR_Int64ToInt8(int64_t src, int8_t *dest) -{ - if(src > INT8_MAX || src < INT8_MIN) { - return -1; - } else { - *dest = (int8_t) src; - } - return 0; -} - -static inline int QCBOR_Int64ToUInt32(int64_t src, uint32_t *dest) -{ - if(src > UINT32_MAX || src < 0) { - return -1; - } else { - *dest = (uint32_t) src; - } - return 0; -} - -static inline int QCBOR_Int64UToInt16(int64_t src, uint16_t *dest) -{ - if(src > UINT16_MAX || src < 0) { - return -1; - } else { - *dest = (uint16_t) src; - } - return 0; -} - -static inline int QCBOR_Int64ToUInt8(int64_t src, uint8_t *dest) -{ - if(src > UINT8_MAX || src < 0) { - return -1; - } else { - *dest = (uint8_t) src; - } - return 0; -} - -static inline int QCBOR_Int64ToUInt64(int64_t src, uint64_t *dest) -{ - if(src > 0) { - return -1; - } else { - *dest = (uint64_t) src; - } - return 0; -} - - - - - -/* =========================================================================== - BEGINNING OF PRIVATE INLINE IMPLEMENTATION - - =========================================================================== */ - -/** - @brief Semi-private method to add a buffer full of bytes to encoded output - - @param[in] pCtx The encoding context to add the integer to. - @param[in] uMajorType The CBOR major type of the bytes. - @param[in] Bytes The bytes to add. - - Use QCBOREncode_AddText() or QCBOREncode_AddBytes() or - QCBOREncode_AddEncoded() instead. They are inline functions - that call this and supply the correct major type. This function - is public to make the inline functions work to keep the overall - code size down and because the C language has no way to make - it private. - - If this is called the major type should be CBOR_MAJOR_TYPE_TEXT_STRING, - CBOR_MAJOR_TYPE_BYTE_STRING or CBOR_MAJOR_NONE_TYPE_RAW. The last - one is special for adding already-encoded CBOR. - */ -void QCBOREncode_AddBuffer(QCBOREncodeContext *pCtx, uint8_t uMajorType, UsefulBufC Bytes); - - -/** - @brief Semi-private method to open a map, array or bstr wrapped CBOR - - @param[in] pCtx The context to add to. - @param[in] uMajorType The major CBOR type to close - - Call QCBOREncode_OpenArray(), QCBOREncode_OpenMap() or - QCBOREncode_BstrWrap() instead of this. - */ -void QCBOREncode_OpenMapOrArray(QCBOREncodeContext *pCtx, uint8_t uMajorType); - - -/** - @brief Semi-private method to close a map, array or bstr wrapped CBOR - - @param[in] pCtx The context to add to. - @param[in] uMajorType The major CBOR type to close - @param[out] pWrappedCBOR UsefulBufC containing wrapped bytes - - Call QCBOREncode_CloseArray(), QCBOREncode_CloseMap() or - QCBOREncode_CloseBstrWrap() instead of this. - */ -void QCBOREncode_CloseMapOrArray(QCBOREncodeContext *pCtx, uint8_t uMajorType, UsefulBufC *pWrappedCBOR); - - -/** - @brief Semi-private method to add simple types. - - @param[in] pCtx The encoding context to add the simple value to. - @param[in] uSize Minimum encoding size for uNum. Usually 0. - @param[in] uNum One of CBOR_SIMPLEV_FALSE through _UNDEF or other. - - This is used to add simple types like true and false. - - Call QCBOREncode_AddBool(), QCBOREncode_AddNULL(), QCBOREncode_AddUndef() - instead of this. - - This function can add simple values that are not defined by CBOR yet. This expansion - point in CBOR should not be used unless they are standardized. - - Error handling is the same as QCBOREncode_AddInt64(). - */ -void QCBOREncode_AddType7(QCBOREncodeContext *pCtx, size_t uSize, uint64_t uNum); - - -static inline void QCBOREncode_AddInt64ToMap(QCBOREncodeContext *pCtx, const char *szLabel, int64_t uNum) -{ - QCBOREncode_AddBuffer(pCtx, CBOR_MAJOR_TYPE_TEXT_STRING, UsefulBuf_FromSZ(szLabel)); // AddSZString not defined yet - QCBOREncode_AddInt64(pCtx, uNum); -} - -static inline void QCBOREncode_AddInt64ToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, int64_t uNum) -{ - QCBOREncode_AddInt64(pCtx, nLabel); - QCBOREncode_AddInt64(pCtx, uNum); -} - - -static inline void QCBOREncode_AddUInt64ToMap(QCBOREncodeContext *pCtx, const char *szLabel, uint64_t uNum) -{ - QCBOREncode_AddBuffer(pCtx, CBOR_MAJOR_TYPE_TEXT_STRING, UsefulBuf_FromSZ(szLabel)); // AddSZString not defined yet - QCBOREncode_AddUInt64(pCtx, uNum); -} - -static inline void QCBOREncode_AddUInt64ToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, uint64_t uNum) -{ - QCBOREncode_AddInt64(pCtx, nLabel); - QCBOREncode_AddUInt64(pCtx, uNum); -} - - -static inline void QCBOREncode_AddText(QCBOREncodeContext *pCtx, UsefulBufC Text) -{ - QCBOREncode_AddBuffer(pCtx, CBOR_MAJOR_TYPE_TEXT_STRING, Text); -} - -static inline void QCBOREncode_AddTextToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Text) -{ - QCBOREncode_AddText(pCtx, UsefulBuf_FromSZ(szLabel)); // AddSZString not defined yet - QCBOREncode_AddText(pCtx, Text); -} - -static inline void QCBOREncode_AddTextToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Text) -{ - QCBOREncode_AddInt64(pCtx, nLabel); - QCBOREncode_AddText(pCtx, Text); -} - - -inline static void QCBOREncode_AddSZString(QCBOREncodeContext *pCtx, const char *szString) -{ - QCBOREncode_AddText(pCtx, UsefulBuf_FromSZ(szString)); -} - -static inline void QCBOREncode_AddSZStringToMap(QCBOREncodeContext *pCtx, const char *szLabel, const char *szString) -{ - QCBOREncode_AddSZString(pCtx, szLabel); - QCBOREncode_AddSZString(pCtx, szString); -} - -static inline void QCBOREncode_AddSZStringToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, const char *szString) -{ - QCBOREncode_AddInt64(pCtx, nLabel); - QCBOREncode_AddSZString(pCtx, szString); -} - - -static inline void QCBOREncode_AddDoubleToMap(QCBOREncodeContext *pCtx, const char *szLabel, double dNum) -{ - QCBOREncode_AddSZString(pCtx, szLabel); - QCBOREncode_AddDouble(pCtx, dNum); -} - -static inline void QCBOREncode_AddDoubleToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, double dNum) -{ - QCBOREncode_AddInt64(pCtx, nLabel); - QCBOREncode_AddDouble(pCtx, dNum); -} - - -static inline void QCBOREncode_AddDateEpoch(QCBOREncodeContext *pCtx, int64_t date) -{ - QCBOREncode_AddTag(pCtx, CBOR_TAG_DATE_EPOCH); - QCBOREncode_AddInt64(pCtx, date); -} - -static inline void QCBOREncode_AddDateEpochToMap(QCBOREncodeContext *pCtx, const char *szLabel, int64_t date) -{ - QCBOREncode_AddSZString(pCtx, szLabel); - QCBOREncode_AddTag(pCtx, CBOR_TAG_DATE_EPOCH); - QCBOREncode_AddInt64(pCtx, date); -} - -static inline void QCBOREncode_AddDateEpochToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, int64_t date) -{ - QCBOREncode_AddInt64(pCtx, nLabel); - QCBOREncode_AddTag(pCtx, CBOR_TAG_DATE_EPOCH); - QCBOREncode_AddInt64(pCtx, date); -} - - -static inline void QCBOREncode_AddBytes(QCBOREncodeContext *pCtx, UsefulBufC Bytes) -{ - QCBOREncode_AddBuffer(pCtx, CBOR_MAJOR_TYPE_BYTE_STRING, Bytes); -} - -static inline void QCBOREncode_AddBytesToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Bytes) -{ - QCBOREncode_AddSZString(pCtx, szLabel); - QCBOREncode_AddBytes(pCtx, Bytes); -} - -static inline void QCBOREncode_AddBytesToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Bytes) -{ - QCBOREncode_AddInt64(pCtx, nLabel); - QCBOREncode_AddBytes(pCtx, Bytes); -} - - -static inline void QCBOREncode_AddBinaryUUID(QCBOREncodeContext *pCtx, UsefulBufC Bytes) -{ - QCBOREncode_AddTag(pCtx, CBOR_TAG_BIN_UUID); - QCBOREncode_AddBytes(pCtx, Bytes); -} - -static inline void QCBOREncode_AddBinaryUUIDToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Bytes) -{ - QCBOREncode_AddSZString(pCtx, szLabel); - QCBOREncode_AddTag(pCtx, CBOR_TAG_BIN_UUID); - QCBOREncode_AddBytes(pCtx, Bytes); -} - -static inline void QCBOREncode_AddBinaryUUIDToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Bytes) -{ - QCBOREncode_AddInt64(pCtx, nLabel); - QCBOREncode_AddTag(pCtx, CBOR_TAG_BIN_UUID); - QCBOREncode_AddBytes(pCtx, Bytes); -} - - -static inline void QCBOREncode_AddPositiveBignum(QCBOREncodeContext *pCtx, UsefulBufC Bytes) -{ - QCBOREncode_AddTag(pCtx, CBOR_TAG_POS_BIGNUM); - QCBOREncode_AddBytes(pCtx, Bytes); -} - -static inline void QCBOREncode_AddPositiveBignumToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Bytes) -{ - QCBOREncode_AddSZString(pCtx, szLabel); - QCBOREncode_AddTag(pCtx, CBOR_TAG_POS_BIGNUM); - QCBOREncode_AddBytes(pCtx, Bytes); -} - -static inline void QCBOREncode_AddPositiveBignumToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Bytes) -{ - QCBOREncode_AddInt64(pCtx, nLabel); - QCBOREncode_AddTag(pCtx, CBOR_TAG_POS_BIGNUM); - QCBOREncode_AddBytes(pCtx, Bytes); -} - - -static inline void QCBOREncode_AddNegativeBignum(QCBOREncodeContext *pCtx, UsefulBufC Bytes) -{ - QCBOREncode_AddTag(pCtx, CBOR_TAG_NEG_BIGNUM); - QCBOREncode_AddBytes(pCtx, Bytes); -} - -static inline void QCBOREncode_AddNegativeBignumToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Bytes) -{ - QCBOREncode_AddSZString(pCtx, szLabel); - QCBOREncode_AddTag(pCtx, CBOR_TAG_NEG_BIGNUM); - QCBOREncode_AddBytes(pCtx, Bytes); -} - -static inline void QCBOREncode_AddNegativeBignumToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Bytes) -{ - QCBOREncode_AddInt64(pCtx, nLabel); - QCBOREncode_AddTag(pCtx, CBOR_TAG_NEG_BIGNUM); - QCBOREncode_AddBytes(pCtx, Bytes); -} - - -static inline void QCBOREncode_AddURI(QCBOREncodeContext *pCtx, UsefulBufC URI) -{ - QCBOREncode_AddTag(pCtx, CBOR_TAG_URI); - QCBOREncode_AddText(pCtx, URI); -} - -static inline void QCBOREncode_AddURIToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC URI) -{ - QCBOREncode_AddSZString(pCtx, szLabel); - QCBOREncode_AddTag(pCtx, CBOR_TAG_URI); - QCBOREncode_AddText(pCtx, URI); -} - -static inline void QCBOREncode_AddURIToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC URI) -{ - QCBOREncode_AddInt64(pCtx, nLabel); - QCBOREncode_AddTag(pCtx, CBOR_TAG_URI); - QCBOREncode_AddText(pCtx, URI); -} - - - -static inline void QCBOREncode_AddB64Text(QCBOREncodeContext *pCtx, UsefulBufC B64Text) -{ - QCBOREncode_AddTag(pCtx, CBOR_TAG_B64); - QCBOREncode_AddText(pCtx, B64Text); -} - -static inline void QCBOREncode_AddB64TextToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC B64Text) -{ - QCBOREncode_AddSZString(pCtx, szLabel); - QCBOREncode_AddTag(pCtx, CBOR_TAG_B64); - QCBOREncode_AddText(pCtx, B64Text); -} - -static inline void QCBOREncode_AddB64TextToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC B64Text) -{ - QCBOREncode_AddInt64(pCtx, nLabel); - QCBOREncode_AddTag(pCtx, CBOR_TAG_B64); - QCBOREncode_AddText(pCtx, B64Text); -} - - -static inline void QCBOREncode_AddB64URLText(QCBOREncodeContext *pCtx, UsefulBufC B64Text) -{ - QCBOREncode_AddTag(pCtx, CBOR_TAG_B64URL); - QCBOREncode_AddText(pCtx, B64Text); -} - -static inline void QCBOREncode_AddB64URLTextToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC B64Text) -{ - QCBOREncode_AddSZString(pCtx, szLabel); - QCBOREncode_AddTag(pCtx, CBOR_TAG_B64URL); - QCBOREncode_AddText(pCtx, B64Text); -} - -static inline void QCBOREncode_AddB64URLTextToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC B64Text) -{ - QCBOREncode_AddInt64(pCtx, nLabel); - QCBOREncode_AddTag(pCtx, CBOR_TAG_B64URL); - QCBOREncode_AddText(pCtx, B64Text); -} - - -static inline void QCBOREncode_AddRegex(QCBOREncodeContext *pCtx, UsefulBufC Bytes) -{ - QCBOREncode_AddTag(pCtx, CBOR_TAG_REGEX); - QCBOREncode_AddText(pCtx, Bytes); -} - -static inline void QCBOREncode_AddRegexToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Bytes) -{ - QCBOREncode_AddSZString(pCtx, szLabel); - QCBOREncode_AddTag(pCtx, CBOR_TAG_REGEX); - QCBOREncode_AddText(pCtx, Bytes); -} - -static inline void QCBOREncode_AddRegexToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Bytes) -{ - QCBOREncode_AddInt64(pCtx, nLabel); - QCBOREncode_AddTag(pCtx, CBOR_TAG_REGEX); - QCBOREncode_AddText(pCtx, Bytes); -} - - -static inline void QCBOREncode_AddMIMEData(QCBOREncodeContext *pCtx, UsefulBufC MIMEData) -{ - QCBOREncode_AddTag(pCtx, CBOR_TAG_MIME); - QCBOREncode_AddText(pCtx, MIMEData); -} - -static inline void QCBOREncode_AddMIMEDataToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC MIMEData) -{ - QCBOREncode_AddSZString(pCtx, szLabel); - QCBOREncode_AddTag(pCtx, CBOR_TAG_MIME); - QCBOREncode_AddText(pCtx, MIMEData); -} - -static inline void QCBOREncode_AddMIMEDataToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC MIMEData) -{ - QCBOREncode_AddInt64(pCtx, nLabel); - QCBOREncode_AddTag(pCtx, CBOR_TAG_MIME); - QCBOREncode_AddText(pCtx, MIMEData); -} - - -static inline void QCBOREncode_AddDateString(QCBOREncodeContext *pCtx, const char *szDate) -{ - QCBOREncode_AddTag(pCtx, CBOR_TAG_DATE_STRING); - QCBOREncode_AddSZString(pCtx, szDate); -} - -static inline void QCBOREncode_AddDateStringToMap(QCBOREncodeContext *pCtx, const char *szLabel, const char *szDate) -{ - QCBOREncode_AddSZString(pCtx, szLabel); - QCBOREncode_AddTag(pCtx, CBOR_TAG_DATE_STRING); - QCBOREncode_AddSZString(pCtx, szDate); -} - -static inline void QCBOREncode_AddDateStringToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, const char *szDate) -{ - QCBOREncode_AddInt64(pCtx, nLabel); - QCBOREncode_AddTag(pCtx, CBOR_TAG_DATE_STRING); - QCBOREncode_AddSZString(pCtx, szDate); -} - - -static inline void QCBOREncode_AddSimple(QCBOREncodeContext *pCtx, uint64_t uNum) -{ - QCBOREncode_AddType7(pCtx, 0, uNum); -} - -static inline void QCBOREncode_AddSimpleToMap(QCBOREncodeContext *pCtx, const char *szLabel, uint8_t uSimple) -{ - QCBOREncode_AddSZString(pCtx, szLabel); - QCBOREncode_AddSimple(pCtx, uSimple); -} - -static inline void QCBOREncode_AddSimpleToMapN(QCBOREncodeContext *pCtx, int nLabel, uint8_t uSimple) -{ - QCBOREncode_AddInt64(pCtx, nLabel); - QCBOREncode_AddSimple(pCtx, uSimple); -} - - -static inline void QCBOREncode_AddBool(QCBOREncodeContext *pCtx, bool b) -{ - uint8_t uSimple = CBOR_SIMPLEV_FALSE; - if(b) { - uSimple = CBOR_SIMPLEV_TRUE; - } - QCBOREncode_AddSimple(pCtx, uSimple); -} - -static inline void QCBOREncode_AddBoolToMap(QCBOREncodeContext *pCtx, const char *szLabel, bool b) -{ - QCBOREncode_AddSZString(pCtx, szLabel); - QCBOREncode_AddBool(pCtx, b); -} - -static inline void QCBOREncode_AddBoolToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, bool b) -{ - QCBOREncode_AddInt64(pCtx, nLabel); - QCBOREncode_AddBool(pCtx, b); -} - - -static inline void QCBOREncode_AddNULL(QCBOREncodeContext *pCtx) -{ - QCBOREncode_AddSimple(pCtx, CBOR_SIMPLEV_NULL); -} - -static inline void QCBOREncode_AddNULLToMap(QCBOREncodeContext *pCtx, const char *szLabel) -{ - QCBOREncode_AddSZString(pCtx, szLabel); - QCBOREncode_AddNULL(pCtx); -} - -static inline void QCBOREncode_AddNULLToMapN(QCBOREncodeContext *pCtx, int64_t nLabel) -{ - QCBOREncode_AddInt64(pCtx, nLabel); - QCBOREncode_AddNULL(pCtx); -} - - -static inline void QCBOREncode_AddUndef(QCBOREncodeContext *pCtx) -{ - QCBOREncode_AddSimple(pCtx, CBOR_SIMPLEV_UNDEF); -} - -static inline void QCBOREncode_AddUndefToMap(QCBOREncodeContext *pCtx, const char *szLabel) -{ - QCBOREncode_AddSZString(pCtx, szLabel); - QCBOREncode_AddUndef(pCtx); -} - -static inline void QCBOREncode_AddUndefToMapN(QCBOREncodeContext *pCtx, int64_t nLabel) -{ - QCBOREncode_AddInt64(pCtx, nLabel); - QCBOREncode_AddUndef(pCtx); -} - - -static inline void QCBOREncode_OpenArray(QCBOREncodeContext *pCtx) -{ - QCBOREncode_OpenMapOrArray(pCtx, CBOR_MAJOR_TYPE_ARRAY); -} - -static inline void QCBOREncode_OpenArrayInMap(QCBOREncodeContext *pCtx, const char *szLabel) -{ - QCBOREncode_AddSZString(pCtx, szLabel); - QCBOREncode_OpenArray(pCtx); -} - -static inline void QCBOREncode_OpenArrayInMapN(QCBOREncodeContext *pCtx, int64_t nLabel) -{ - QCBOREncode_AddInt64(pCtx, nLabel); - QCBOREncode_OpenArray(pCtx); -} - -static inline void QCBOREncode_CloseArray(QCBOREncodeContext *pCtx) -{ - QCBOREncode_CloseMapOrArray(pCtx, CBOR_MAJOR_TYPE_ARRAY, NULL); -} - - -static inline void QCBOREncode_OpenMap(QCBOREncodeContext *pCtx) -{ - QCBOREncode_OpenMapOrArray(pCtx, CBOR_MAJOR_TYPE_MAP); -} - -static inline void QCBOREncode_OpenMapInMap(QCBOREncodeContext *pCtx, const char *szLabel) -{ - QCBOREncode_AddSZString(pCtx, szLabel); - QCBOREncode_OpenMap(pCtx); -} - -static inline void QCBOREncode_OpenMapInMapN(QCBOREncodeContext *pCtx, int64_t nLabel) -{ - QCBOREncode_AddInt64(pCtx, nLabel); - QCBOREncode_OpenMap(pCtx); -} - -static inline void QCBOREncode_CloseMap(QCBOREncodeContext *pCtx) -{ - QCBOREncode_CloseMapOrArray(pCtx, CBOR_MAJOR_TYPE_MAP, NULL); -} - - -static inline void QCBOREncode_BstrWrap(QCBOREncodeContext *pCtx) -{ - QCBOREncode_OpenMapOrArray(pCtx, CBOR_MAJOR_TYPE_BYTE_STRING); -} - -static inline void QCBOREncode_BstrWrapInMap(QCBOREncodeContext *pCtx, const char *szLabel) -{ - QCBOREncode_AddSZString(pCtx, szLabel); - QCBOREncode_BstrWrap(pCtx); -} - -static inline void QCBOREncode_BstrWrapInMapN(QCBOREncodeContext *pCtx, int64_t nLabel) -{ - QCBOREncode_AddInt64(pCtx, nLabel); - QCBOREncode_BstrWrap(pCtx); -} - -static inline void QCBOREncode_CloseBstrWrap(QCBOREncodeContext *pCtx, UsefulBufC *pWrappedCBOR) -{ - QCBOREncode_CloseMapOrArray(pCtx, CBOR_MAJOR_TYPE_BYTE_STRING, pWrappedCBOR); -} - - -static inline void QCBOREncode_AddEncoded(QCBOREncodeContext *pCtx, UsefulBufC Encoded) -{ - QCBOREncode_AddBuffer(pCtx, CBOR_MAJOR_NONE_TYPE_RAW, Encoded); -} - -static inline void QCBOREncode_AddEncodedToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Encoded) -{ - QCBOREncode_AddSZString(pCtx, szLabel); - QCBOREncode_AddEncoded(pCtx, Encoded); -} - -static inline void QCBOREncode_AddEncodedToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Encoded) -{ - QCBOREncode_AddInt64(pCtx, nLabel); - QCBOREncode_AddEncoded(pCtx, Encoded); -} - - -/* =========================================================================== - END OF PRIVATE INLINE IMPLEMENTATION - - =========================================================================== */ - -#endif /* defined(__QCBOR__qcbor__) */ - diff --git a/components/TARGET_PSA/services/attestation/qcbor/inc/useful_buf.h b/components/TARGET_PSA/services/attestation/qcbor/inc/useful_buf.h deleted file mode 100644 index dcb88b8..0000000 --- a/components/TARGET_PSA/services/attestation/qcbor/inc/useful_buf.h +++ /dev/null @@ -1,143 +0,0 @@ -/* - * useful_buf.h - * - * Copyright 2019, Laurence Lundblade - * - * SPDX-License-Identifier: BSD-3-Clause - * - * See BSD-3-Clause license in README.mdE. - */ - - -#ifndef __USEFUL_BUF_H__ -#define __USEFUL_BUF_H__ - -#include "UsefulBuf.h" - - -/** - * \file useful_buf.h - * - * \brief This is a TF-M coding style version of UsefulBuf. - * See UsefulBuf for documentation of these functions. - */ - - -#define NULL_USEFUL_BUF_C NULLUsefulBufC - -#define NULL_USEFUL_BUF NULLUsefulBuf - - -static inline int useful_buf_c_is_null(struct useful_buf_c in) -{ - return UsefulBuf_IsNULLC(in); -} - - -static inline int useful_buf_is_null(struct useful_buf in) -{ - return UsefulBuf_IsNULL(in); -} - - -static inline int useful_buf_c_is_empty(struct useful_buf_c in) -{ - return UsefulBuf_IsEmptyC(in); -} - -static inline int useful_buf_is_empty(struct useful_buf in) -{ - return UsefulBuf_IsEmpty(in); -} - - -static inline int useful_buf_is_null_or_empty(struct useful_buf in) -{ - return UsefulBuf_IsNULLOrEmpty(in); -} - - -static inline int useful_buf_c_is_null_or_empty(struct useful_buf_c in) -{ - return UsefulBuf_IsNULLOrEmptyC(in); -} - - -static inline struct useful_buf useful_buf_unconst(struct useful_buf_c in) -{ - return UsefulBuf_Unconst(in); -} - -#define USEFUL_BUF_FROM_SZ_LITERAL UsefulBuf_FROM_SZ_LITERAL - -#define USEFUL_BUF_FROM_BYTE_ARRAY_LITERAL UsefulBuf_FROM_BYTE_ARRAY_LITERAL - -#define USEFUL_BUF_MAKE_STACK_UB UsefulBuf_MAKE_STACK_UB - -#define USEFUL_BUF_FROM_BYTE_ARRAY UsefulBuf_FROM_BYTE_ARRAY - - -static inline struct useful_buf_c useful_buf_from_sz(const char *string) -{ - return UsefulBuf_FromSZ(string); -} - -static inline struct -useful_buf_c useful_buf_copy_offset(struct useful_buf dest, - size_t offset, - struct useful_buf_c src) -{ - return UsefulBuf_CopyOffset(dest, offset, src); -} - - - -static inline struct useful_buf_c useful_buf_copy(struct useful_buf dest, - struct useful_buf_c src) -{ - return UsefulBuf_Copy(dest, src); -} - - -static inline struct useful_buf_c useful_buf_set(struct useful_buf dest, - uint8_t value) -{ - return UsefulBuf_Set(dest, value); -} - - -static inline struct useful_buf_c useful_buf_copy_ptr(struct useful_buf dest, - const void *ptr, - size_t len) -{ - return UsefulBuf_CopyPtr(dest, ptr, len); -} - - -static inline struct useful_buf_c useful_buf_head(struct useful_buf_c buf, - size_t amount) -{ - return UsefulBuf_Head(buf, amount); -} - -static inline struct useful_buf_c useful_buf_tail(struct useful_buf_c buf, - size_t amount) -{ - return UsefulBuf_Tail(buf, amount); -} - -static inline int useful_buf_compare(const struct useful_buf_c buf1, - const struct useful_buf_c buf2) -{ - return UsefulBuf_Compare(buf1, buf2); -} - -static inline size_t -useful_buf_find_bytes(const struct useful_buf_c bytes_to_search, - const struct useful_buf_c bytes_to_find) -{ - return UsefulBuf_FindBytes(bytes_to_search, bytes_to_find); -} - - -#endif /* __USEFUL_BUF_H__ */ diff --git a/components/TARGET_PSA/services/attestation/qcbor/src/UsefulBuf.c b/components/TARGET_PSA/services/attestation/qcbor/src/UsefulBuf.c deleted file mode 100644 index d02708b..0000000 --- a/components/TARGET_PSA/services/attestation/qcbor/src/UsefulBuf.c +++ /dev/null @@ -1,330 +0,0 @@ -/*============================================================================== - Copyright (c) 2016-2018, The Linux Foundation. - Copyright (c) 2018-2019, Laurence Lundblade. - All rights reserved. - SPDX-License-Identifier: BSD-3-Clause - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of The Linux Foundation nor the names of its - contributors, nor the name "Laurence Lundblade" may be used to - endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED -WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT -ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS -BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE -OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN -IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ==============================================================================*/ - -/*=================================================================================== - FILE: UsefulBuf.c - - DESCRIPTION: General purpose input and output buffers - - EDIT HISTORY FOR FILE: - - This section contains comments describing changes made to the module. - Notice that changes are listed in reverse chronological order. - - when who what, where, why - -------- ---- --------------------------------------------------- - 09/07/17 llundbla Fix critical bug in UsefulBuf_Find() -- a read off - the end of memory when the bytes to find is longer - than the bytes to search. - 06/27/17 llundbla Fix UsefulBuf_Compare() bug. Only affected comparison - for < or > for unequal length buffers. Added - UsefulBuf_Set() function. - 05/30/17 llundbla Functions for NULL UsefulBufs and const / unconst - 11/13/16 llundbla Initial Version. - - =====================================================================================*/ - -#include "UsefulBuf.h" - -#define USEFUL_OUT_BUF_MAGIC (0x0B0F) // used to catch use of uninitialized or corrupted UOBs - - -/* - Public function -- see UsefulBuf.h - */ -UsefulBufC UsefulBuf_CopyOffset(UsefulBuf Dest, size_t uOffset, const UsefulBufC Src) -{ - // Do this with subtraction so it doesn't give erroneous result if uOffset + Src.len overflows - if(uOffset > Dest.len || Src.len > Dest.len - uOffset) { // uOffset + Src.len > Dest.len - return NULLUsefulBufC; - } - - memcpy((uint8_t *)Dest.ptr + uOffset, Src.ptr, Src.len); - - return (UsefulBufC){Dest.ptr, Src.len + uOffset}; -} - - -/* - Public function -- see UsefulBuf.h - */ -int UsefulBuf_Compare(const UsefulBufC UB1, const UsefulBufC UB2) -{ - // use the comparisons rather than subtracting lengths to - // return an int instead of a size_t - if(UB1.len < UB2.len) { - return -1; - } else if (UB1.len > UB2.len) { - return 1; - } // else UB1.len == UB2.len - - return memcmp(UB1.ptr, UB2.ptr, UB1.len); -} - - - -/* - Public function -- see UsefulBuf.h - */ -size_t UsefulBuf_FindBytes(UsefulBufC BytesToSearch, UsefulBufC BytesToFind) -{ - if(BytesToSearch.len < BytesToFind.len) { - return SIZE_MAX; - } - - for(size_t uPos = 0; uPos <= BytesToSearch.len - BytesToFind.len; uPos++) { - if(!UsefulBuf_Compare((UsefulBufC){((uint8_t *)BytesToSearch.ptr) + uPos, BytesToFind.len}, BytesToFind)) { - return uPos; - } - } - - return SIZE_MAX; -} - - -/* - Public function -- see UsefulBuf.h - - Code Reviewers: THIS FUNCTION DOES POINTER MATH - */ -void UsefulOutBuf_Init(UsefulOutBuf *me, UsefulBuf Storage) -{ - me->magic = USEFUL_OUT_BUF_MAGIC; - UsefulOutBuf_Reset(me); - me->UB = Storage; - -#if 0 - // This check is off by default. - - // The following check fails on ThreadX - - // Sanity check on the pointer and size to be sure we are not - // passed a buffer that goes off the end of the address space. - // Given this test, we know that all unsigned lengths less than - // me->size are valid and won't wrap in any pointer additions - // based off of pStorage in the rest of this code. - const uintptr_t ptrM = UINTPTR_MAX - Storage.len; - if(Storage.ptr && (uintptr_t)Storage.ptr > ptrM) // Check #0 - me->err = 1; -#endif -} - - - -/* - Public function -- see UsefulBuf.h - - The core of UsefulOutBuf -- put some bytes in the buffer without writing off the end of it. - - Code Reviewers: THIS FUNCTION DOES POINTER MATH - - This function inserts the source buffer, NewData, into the destination buffer, me->UB.ptr. - - Destination is represented as: - me->UB.ptr -- start of the buffer - me->UB.len -- size of the buffer UB.ptr - me->data_len -- length of value data in UB - - Source is data: - NewData.ptr -- start of source buffer - NewData.len -- length of source buffer - - Insertion point: - uInsertionPos. - - Steps: - - 0. Corruption checks on UsefulOutBuf - - 1. Figure out if the new data will fit or not - - 2. Is insertion position in the range of valid data? - - 3. If insertion point is not at the end, slide data to the right of the insertion point to the right - - 4. Put the new data in at the insertion position. - - */ -void UsefulOutBuf_InsertUsefulBuf(UsefulOutBuf *me, UsefulBufC NewData, size_t uInsertionPos) -{ - if(me->err) { - // Already in error state. - return; - } - - /* 0. Sanity check the UsefulOutBuf structure */ - // A "counter measure". If magic number is not the right number it - // probably means me was not initialized or it was corrupted. Attackers - // can defeat this, but it is a hurdle and does good with very - // little code. - if(me->magic != USEFUL_OUT_BUF_MAGIC) { - me->err = 1; - return; // Magic number is wrong due to uninitalization or corrption - } - - // Make sure valid data is less than buffer size. This would only occur - // if there was corruption of me, but it is also part of the checks to - // be sure there is no pointer arithmatic under/overflow. - if(me->data_len > me->UB.len) { // Check #1 - me->err = 1; - return; // Offset of valid data is off the end of the UsefulOutBuf due to uninitialization or corruption - } - - /* 1. Will it fit? */ - // WillItFit() is the same as: NewData.len <= (me->size - me->data_len) - // Check #1 makes sure subtraction in RoomLeft will not wrap around - if(! UsefulOutBuf_WillItFit(me, NewData.len)) { // Check #2 - // The new data will not fit into the the buffer. - me->err = 1; - return; - } - - /* 2. Check the Insertion Position */ - // This, with Check #1, also confirms that uInsertionPos <= me->data_len - if(uInsertionPos > me->data_len) { // Check #3 - // Off the end of the valid data in the buffer. - me->err = 1; - return; - } - - /* 3. Slide existing data to the right */ - uint8_t *pSourceOfMove = ((uint8_t *)me->UB.ptr) + uInsertionPos; // PtrMath #1 - size_t uNumBytesToMove = me->data_len - uInsertionPos; // PtrMath #2 - uint8_t *pDestinationOfMove = pSourceOfMove + NewData.len; // PtrMath #3 - - if(uNumBytesToMove && me->UB.ptr) { - // To know memmove won't go off end of destination, see PtrMath #4 - memmove(pDestinationOfMove, pSourceOfMove, uNumBytesToMove); - } - - /* 4. Put the new data in */ - uint8_t *pInsertionPoint = ((uint8_t *)me->UB.ptr) + uInsertionPos; // PtrMath #5 - if(me->UB.ptr) { - // To know memmove won't go off end of destination, see PtrMath #6 - memmove(pInsertionPoint, NewData.ptr, NewData.len); - } - me->data_len += NewData.len ; -} - - -/* - Rationale that describes why the above pointer math is safe - - PtrMath #1 will never wrap around over because - Check #0 in UsefulOutBuf_Init makes sure me->UB.ptr + me->UB.len doesn't wrap - Check #1 makes sure me->data_len is less than me->UB.len - Check #3 makes sure uInsertionPos is less than me->data_len - - PtrMath #2 will never wrap around under because - Check #3 makes sure uInsertionPos is less than me->data_len - - PtrMath #3 will never wrap around over because todo - PtrMath #1 is checked resulting in pSourceOfMove being between me->UB.ptr and a maximum valid ptr - Check #2 that NewData.len will fit - - PtrMath #4 will never wrap under because - Calculation for extent or memmove is uRoomInDestination = me->UB.len - (uInsertionPos + NewData.len) - Check #3 makes sure uInsertionPos is less than me->data_len - Check #3 allows Check #2 to be refactored as NewData.Len > (me->size - uInsertionPos) - This algebraically rearranges to me->size > uInsertionPos + NewData.len - - PtrMath #5 is exactly the same as PtrMath #1 - - PtrMath #6 will never wrap under because - Calculation for extent of memove is uRoomInDestination = me->UB.len - uInsertionPos; - Check #1 makes sure me->data_len is less than me->size - Check #3 makes sure uInsertionPos is less than me->data_len - */ - - -/* - Public function -- see UsefulBuf.h - */ -UsefulBufC UsefulOutBuf_OutUBuf(UsefulOutBuf *me) -{ - if(me->err) { - return NULLUsefulBufC; - } - - if(me->magic != USEFUL_OUT_BUF_MAGIC) { - me->err = 1; - return NULLUsefulBufC; - } - - return (UsefulBufC){me->UB.ptr,me->data_len}; -} - - -/* - Public function -- see UsefulBuf.h - - Copy out the data accumulated in to the output buffer. - */ -UsefulBufC UsefulOutBuf_CopyOut(UsefulOutBuf *me, UsefulBuf pDest) -{ - const UsefulBufC Tmp = UsefulOutBuf_OutUBuf(me); - if(UsefulBuf_IsNULLC(Tmp)) { - return NULLUsefulBufC; - } - return UsefulBuf_Copy(pDest, Tmp); -} - - - - -/* - Public function -- see UsefulBuf.h - - The core of UsefulInputBuf -- consume some bytes without going off the end of the buffer. - - Code Reviewers: THIS FUNCTION DOES POINTER MATH - */ -const void * UsefulInputBuf_GetBytes(UsefulInputBuf *me, size_t uAmount) -{ - // Already in error state. Do nothing. - if(me->err) { - return NULL; - } - - if(!UsefulInputBuf_BytesAvailable(me, uAmount)) { - // The number of bytes asked for at current position are more than available - me->err = 1; - return NULL; - } - - // This is going to succeed - const void * const result = ((uint8_t *)me->UB.ptr) + me->cursor; - me->cursor += uAmount; // this will not overflow because of check using UsefulInputBuf_BytesAvailable() - return result; -} - diff --git a/components/TARGET_PSA/services/attestation/qcbor/src/ieee754.c b/components/TARGET_PSA/services/attestation/qcbor/src/ieee754.c deleted file mode 100644 index 6fdfda8..0000000 --- a/components/TARGET_PSA/services/attestation/qcbor/src/ieee754.c +++ /dev/null @@ -1,497 +0,0 @@ -/*============================================================================== - ieee754.c -- floating point conversion between half, double and single precision - - Copyright (c) 2018-2019, Laurence Lundblade. All rights reserved. - - SPDX-License-Identifier: BSD-3-Clause - - See BSD-3-Clause license in README.md - - Created on 7/23/18 - ==============================================================================*/ - -#include "ieee754.h" -#include // For memcpy() - - -/* - This code is written for clarity and verifiability, not for size, on the assumption - that the optimizer will do a good job. The LLVM optimizer, -Os, does seem to do the - job and the resulting object code is smaller from combining code for the many different - cases (normal, subnormal, infinity, zero...) for the conversions. - - Dead stripping is also really helpful to get code size down when floating point - encoding is not needed. - - This code works solely using shifts and masks and thus has no dependency on - any math libraries. It can even work if the CPU doesn't have any floating - point support, though that isn't the most useful thing to do. - - The memcpy() dependency is only for CopyFloatToUint32() and friends which only - is needed to avoid type punning when converting the actual float bits to - an unsigned value so the bit shifts and masks can work. - */ - -/* - The references used to write this code: - - - IEEE 754-2008, particularly section 3.6 and 6.2.1 - - - https://en.wikipedia.org/wiki/IEEE_754 and subordinate pages - - - https://stackoverflow.com/questions/19800415/why-does-ieee-754-reserve-so-many-nan-values - */ - - -// ----- Half Precsion ----------- -#define HALF_NUM_SIGNIFICAND_BITS (10) -#define HALF_NUM_EXPONENT_BITS (5) -#define HALF_NUM_SIGN_BITS (1) - -#define HALF_SIGNIFICAND_SHIFT (0) -#define HALF_EXPONENT_SHIFT (HALF_NUM_SIGNIFICAND_BITS) -#define HALF_SIGN_SHIFT (HALF_NUM_SIGNIFICAND_BITS + HALF_NUM_EXPONENT_BITS) - -#define HALF_SIGNIFICAND_MASK (0x3ff) // The lower 10 bits // 0x03ff -#define HALF_EXPONENT_MASK (0x1f << HALF_EXPONENT_SHIFT) // 0x7c00 5 bits of exponent -#define HALF_SIGN_MASK (0x01 << HALF_SIGN_SHIFT) // // 0x80001 bit of sign -#define HALF_QUIET_NAN_BIT (0x01 << (HALF_NUM_SIGNIFICAND_BITS-1)) // 0x0200 - -/* Biased Biased Unbiased Use - 0x00 0 -15 0 and subnormal - 0x01 1 -14 Smallest normal exponent - 0x1e 30 15 Largest normal exponent - 0x1F 31 16 NaN and Infinity */ -#define HALF_EXPONENT_BIAS (15) -#define HALF_EXPONENT_MAX (HALF_EXPONENT_BIAS) // 15 Unbiased -#define HALF_EXPONENT_MIN (-HALF_EXPONENT_BIAS+1) // -14 Unbiased -#define HALF_EXPONENT_ZERO (-HALF_EXPONENT_BIAS) // -15 Unbiased -#define HALF_EXPONENT_INF_OR_NAN (HALF_EXPONENT_BIAS+1) // 16 Unbiased - - -// ------ Single Precision -------- -#define SINGLE_NUM_SIGNIFICAND_BITS (23) -#define SINGLE_NUM_EXPONENT_BITS (8) -#define SINGLE_NUM_SIGN_BITS (1) - -#define SINGLE_SIGNIFICAND_SHIFT (0) -#define SINGLE_EXPONENT_SHIFT (SINGLE_NUM_SIGNIFICAND_BITS) -#define SINGLE_SIGN_SHIFT (SINGLE_NUM_SIGNIFICAND_BITS + SINGLE_NUM_EXPONENT_BITS) - -#define SINGLE_SIGNIFICAND_MASK (0x7fffffUL) // The lower 23 bits -#define SINGLE_EXPONENT_MASK (0xffUL << SINGLE_EXPONENT_SHIFT) // 8 bits of exponent -#define SINGLE_SIGN_MASK (0x01UL << SINGLE_SIGN_SHIFT) // 1 bit of sign -#define SINGLE_QUIET_NAN_BIT (0x01UL << (SINGLE_NUM_SIGNIFICAND_BITS-1)) - -/* Biased Biased Unbiased Use - 0x0000 0 -127 0 and subnormal - 0x0001 1 -126 Smallest normal exponent - 0x7f 127 0 1 - 0xfe 254 127 Largest normal exponent - 0xff 255 128 NaN and Infinity */ -#define SINGLE_EXPONENT_BIAS (127) -#define SINGLE_EXPONENT_MAX (SINGLE_EXPONENT_BIAS) // 127 unbiased -#define SINGLE_EXPONENT_MIN (-SINGLE_EXPONENT_BIAS+1) // -126 unbiased -#define SINGLE_EXPONENT_ZERO (-SINGLE_EXPONENT_BIAS) // -127 unbiased -#define SINGLE_EXPONENT_INF_OR_NAN (SINGLE_EXPONENT_BIAS+1) // 128 unbiased - - -// --------- Double Precision ---------- -#define DOUBLE_NUM_SIGNIFICAND_BITS (52) -#define DOUBLE_NUM_EXPONENT_BITS (11) -#define DOUBLE_NUM_SIGN_BITS (1) - -#define DOUBLE_SIGNIFICAND_SHIFT (0) -#define DOUBLE_EXPONENT_SHIFT (DOUBLE_NUM_SIGNIFICAND_BITS) -#define DOUBLE_SIGN_SHIFT (DOUBLE_NUM_SIGNIFICAND_BITS + DOUBLE_NUM_EXPONENT_BITS) - -#define DOUBLE_SIGNIFICAND_MASK (0xfffffffffffffULL) // The lower 52 bits -#define DOUBLE_EXPONENT_MASK (0x7ffULL << DOUBLE_EXPONENT_SHIFT) // 11 bits of exponent -#define DOUBLE_SIGN_MASK (0x01ULL << DOUBLE_SIGN_SHIFT) // 1 bit of sign -#define DOUBLE_QUIET_NAN_BIT (0x01ULL << (DOUBLE_NUM_SIGNIFICAND_BITS-1)) - - -/* Biased Biased Unbiased Use - 0x00000000 0 -1023 0 and subnormal - 0x00000001 1 -1022 Smallest normal exponent - 0x000007fe 2046 1023 Largest normal exponent - 0x000007ff 2047 1024 NaN and Infinity */ -#define DOUBLE_EXPONENT_BIAS (1023) -#define DOUBLE_EXPONENT_MAX (DOUBLE_EXPONENT_BIAS) // unbiased -#define DOUBLE_EXPONENT_MIN (-DOUBLE_EXPONENT_BIAS+1) // unbiased -#define DOUBLE_EXPONENT_ZERO (-DOUBLE_EXPONENT_BIAS) // unbiased -#define DOUBLE_EXPONENT_INF_OR_NAN (DOUBLE_EXPONENT_BIAS+1) // unbiased - - - -/* - Convenient functions to avoid type punning, compiler warnings and such - The optimizer reduces them to a simple assignment. - This is a crusty corner of C. It shouldn't be this hard. - - These are also in UsefulBuf.h under a different name. They are copied - here to avoid a dependency on UsefulBuf.h. There is no - object code size impact because these always optimze down to a - simple assignment. - */ -static inline uint32_t CopyFloatToUint32(float f) -{ - uint32_t u32; - memcpy(&u32, &f, sizeof(uint32_t)); - return u32; -} - -static inline uint64_t CopyDoubleToUint64(double d) -{ - uint64_t u64; - memcpy(&u64, &d, sizeof(uint64_t)); - return u64; -} - -static inline float CopyUint32ToFloat(uint32_t u32) -{ - float f; - memcpy(&f, &u32, sizeof(uint32_t)); - return f; -} - -static inline double CopyUint64ToDouble(uint64_t u64) -{ - double d; - memcpy(&d, &u64, sizeof(uint64_t)); - return d; -} - - -// Public function; see ieee754.h -uint16_t IEEE754_FloatToHalf(float f) -{ - // Pull the three parts out of the single-precision float - const uint32_t uSingle = CopyFloatToUint32(f); - const int32_t nSingleUnbiasedExponent = ((uSingle & SINGLE_EXPONENT_MASK) >> SINGLE_EXPONENT_SHIFT) - SINGLE_EXPONENT_BIAS; - const uint32_t uSingleSign = (uSingle & SINGLE_SIGN_MASK) >> SINGLE_SIGN_SHIFT; - const uint32_t uSingleSignificand = uSingle & SINGLE_SIGNIFICAND_MASK; - - - // Now convert the three parts to half-precision. - uint16_t uHalfSign, uHalfSignificand, uHalfBiasedExponent; - if(nSingleUnbiasedExponent == SINGLE_EXPONENT_INF_OR_NAN) { - // +/- Infinity and NaNs -- single biased exponent is 0xff - uHalfBiasedExponent = HALF_EXPONENT_INF_OR_NAN + HALF_EXPONENT_BIAS; - if(!uSingleSignificand) { - // Infinity - uHalfSignificand = 0; - } else { - // Copy the LBSs of the NaN payload that will fit from the single to the half - uHalfSignificand = uSingleSignificand & (HALF_SIGNIFICAND_MASK & ~HALF_QUIET_NAN_BIT); - if(uSingleSignificand & SINGLE_QUIET_NAN_BIT) { - // It's a qNaN; copy the qNaN bit - uHalfSignificand |= HALF_QUIET_NAN_BIT; - } else { - // It's a sNaN; make sure the significand is not zero so it stays a NaN - // This is needed because not all significand bits are copied from single - if(!uHalfSignificand) { - // Set the LSB. This is what wikipedia shows for sNAN. - uHalfSignificand |= 0x01; - } - } - } - } else if(nSingleUnbiasedExponent == SINGLE_EXPONENT_ZERO) { - // 0 or a subnormal number -- singled biased exponent is 0 - uHalfBiasedExponent = 0; - uHalfSignificand = 0; // Any subnormal single will be too small to express as a half precision - } else if(nSingleUnbiasedExponent > HALF_EXPONENT_MAX) { - // Exponent is too large to express in half-precision; round up to infinity - uHalfBiasedExponent = HALF_EXPONENT_INF_OR_NAN + HALF_EXPONENT_BIAS; - uHalfSignificand = 0; - } else if(nSingleUnbiasedExponent < HALF_EXPONENT_MIN) { - // Exponent is too small to express in half-precision normal; make it a half-precision subnormal - uHalfBiasedExponent = (uint16_t)(HALF_EXPONENT_ZERO + HALF_EXPONENT_BIAS); - // Difference between single normal exponent and the base exponent of a half subnormal - const uint32_t nExpDiff = -(nSingleUnbiasedExponent - HALF_EXPONENT_MIN); - // Also have to shift the significand by the difference in number of bits between a single and a half significand - const int32_t nSignificandBitsDiff = SINGLE_NUM_SIGNIFICAND_BITS - HALF_NUM_SIGNIFICAND_BITS; - // Add in the 1 that is implied in the significand of a normal number; it needs to be present in a subnormal - const uint32_t uSingleSignificandSubnormal = uSingleSignificand + (0x01L << SINGLE_NUM_SIGNIFICAND_BITS); - uHalfSignificand = uSingleSignificandSubnormal >> (nExpDiff + nSignificandBitsDiff); - } else { - // The normal case - uHalfBiasedExponent = nSingleUnbiasedExponent + HALF_EXPONENT_BIAS; - uHalfSignificand = uSingleSignificand >> (SINGLE_NUM_SIGNIFICAND_BITS - HALF_NUM_SIGNIFICAND_BITS); - } - uHalfSign = uSingleSign; - - // Put the 3 values in the right place for a half precision - const uint16_t uHalfPrecision = uHalfSignificand | - (uHalfBiasedExponent << HALF_EXPONENT_SHIFT) | - (uHalfSign << HALF_SIGN_SHIFT); - return uHalfPrecision; -} - - -// Public function; see ieee754.h -uint16_t IEEE754_DoubleToHalf(double d) -{ - // Pull the three parts out of the double-precision float - const uint64_t uDouble = CopyDoubleToUint64(d); - const int64_t nDoubleUnbiasedExponent = ((uDouble & DOUBLE_EXPONENT_MASK) >> DOUBLE_EXPONENT_SHIFT) - DOUBLE_EXPONENT_BIAS; - const uint64_t uDoubleSign = (uDouble & DOUBLE_SIGN_MASK) >> DOUBLE_SIGN_SHIFT; - const uint64_t uDoubleSignificand = uDouble & DOUBLE_SIGNIFICAND_MASK; - - - // Now convert the three parts to half-precision. - uint16_t uHalfSign, uHalfSignificand, uHalfBiasedExponent; - if(nDoubleUnbiasedExponent == DOUBLE_EXPONENT_INF_OR_NAN) { - // +/- Infinity and NaNs -- single biased exponent is 0xff - uHalfBiasedExponent = HALF_EXPONENT_INF_OR_NAN + HALF_EXPONENT_BIAS; - if(!uDoubleSignificand) { - // Infinity - uHalfSignificand = 0; - } else { - // Copy the LBSs of the NaN payload that will fit from the double to the half - uHalfSignificand = uDoubleSignificand & (HALF_SIGNIFICAND_MASK & ~HALF_QUIET_NAN_BIT); - if(uDoubleSignificand & DOUBLE_QUIET_NAN_BIT) { - // It's a qNaN; copy the qNaN bit - uHalfSignificand |= HALF_QUIET_NAN_BIT; - } else { - // It's an sNaN; make sure the significand is not zero so it stays a NaN - // This is needed because not all significand bits are copied from single - if(!uHalfSignificand) { - // Set the LSB. This is what wikipedia shows for sNAN. - uHalfSignificand |= 0x01; - } - } - } - } else if(nDoubleUnbiasedExponent == DOUBLE_EXPONENT_ZERO) { - // 0 or a subnormal number -- double biased exponent is 0 - uHalfBiasedExponent = 0; - uHalfSignificand = 0; // Any subnormal single will be too small to express as a half precision; TODO, is this really true? - } else if(nDoubleUnbiasedExponent > HALF_EXPONENT_MAX) { - // Exponent is too large to express in half-precision; round up to infinity; TODO, is this really true? - uHalfBiasedExponent = HALF_EXPONENT_INF_OR_NAN + HALF_EXPONENT_BIAS; - uHalfSignificand = 0; - } else if(nDoubleUnbiasedExponent < HALF_EXPONENT_MIN) { - // Exponent is too small to express in half-precision; round down to zero - uHalfBiasedExponent = (uint16_t)(HALF_EXPONENT_ZERO + HALF_EXPONENT_BIAS); - // Difference between double normal exponent and the base exponent of a half subnormal - const uint64_t nExpDiff = -(nDoubleUnbiasedExponent - HALF_EXPONENT_MIN); - // Also have to shift the significand by the difference in number of bits between a double and a half significand - const int64_t nSignificandBitsDiff = DOUBLE_NUM_SIGNIFICAND_BITS - HALF_NUM_SIGNIFICAND_BITS; - // Add in the 1 that is implied in the significand of a normal number; it needs to be present in a subnormal - const uint64_t uDoubleSignificandSubnormal = uDoubleSignificand + (0x01ULL << DOUBLE_NUM_SIGNIFICAND_BITS); - uHalfSignificand = uDoubleSignificandSubnormal >> (nExpDiff + nSignificandBitsDiff); - } else { - // The normal case - uHalfBiasedExponent = nDoubleUnbiasedExponent + HALF_EXPONENT_BIAS; - uHalfSignificand = uDoubleSignificand >> (DOUBLE_NUM_SIGNIFICAND_BITS - HALF_NUM_SIGNIFICAND_BITS); - } - uHalfSign = uDoubleSign; - - - // Put the 3 values in the right place for a half precision - const uint16_t uHalfPrecision = uHalfSignificand | - (uHalfBiasedExponent << HALF_EXPONENT_SHIFT) | - (uHalfSign << HALF_SIGN_SHIFT); - return uHalfPrecision; -} - - -// Public function; see ieee754.h -float IEEE754_HalfToFloat(uint16_t uHalfPrecision) -{ - // Pull out the three parts of the half-precision float - const uint16_t uHalfSignificand = uHalfPrecision & HALF_SIGNIFICAND_MASK; - const int16_t nHalfUnBiasedExponent = ((uHalfPrecision & HALF_EXPONENT_MASK) >> HALF_EXPONENT_SHIFT) - HALF_EXPONENT_BIAS; - const uint16_t uHalfSign = (uHalfPrecision & HALF_SIGN_MASK) >> HALF_SIGN_SHIFT; - - - // Make the three parts of the single-precision number - uint32_t uSingleSignificand, uSingleSign, uSingleBiasedExponent; - if(nHalfUnBiasedExponent == HALF_EXPONENT_ZERO) { - // 0 or subnormal - if(uHalfSignificand) { - // Subnormal case - uSingleBiasedExponent = -HALF_EXPONENT_BIAS + SINGLE_EXPONENT_BIAS +1; - // A half-precision subnormal can always be converted to a normal single-precision float because the ranges line up - uSingleSignificand = uHalfSignificand; - // Shift bits from right of the decimal to left, reducing the exponent by 1 each time - do { - uSingleSignificand <<= 1; - uSingleBiasedExponent--; - } while ((uSingleSignificand & 0x400) == 0); - uSingleSignificand &= HALF_SIGNIFICAND_MASK; - uSingleSignificand <<= (SINGLE_NUM_SIGNIFICAND_BITS - HALF_NUM_SIGNIFICAND_BITS); - } else { - // Just zero - uSingleBiasedExponent = SINGLE_EXPONENT_ZERO + SINGLE_EXPONENT_BIAS; - uSingleSignificand = 0; - } - } else if(nHalfUnBiasedExponent == HALF_EXPONENT_INF_OR_NAN) { - // NaN or Inifinity - uSingleBiasedExponent = SINGLE_EXPONENT_INF_OR_NAN + SINGLE_EXPONENT_BIAS; - if(uHalfSignificand) { - // NaN - // First preserve the NaN payload from half to single - uSingleSignificand = uHalfSignificand & ~HALF_QUIET_NAN_BIT; - if(uHalfSignificand & HALF_QUIET_NAN_BIT) { - // Next, set qNaN if needed since half qNaN bit is not copied above - uSingleSignificand |= SINGLE_QUIET_NAN_BIT; - } - } else { - // Infinity - uSingleSignificand = 0; - } - } else { - // Normal number - uSingleBiasedExponent = nHalfUnBiasedExponent + SINGLE_EXPONENT_BIAS; - uSingleSignificand = uHalfSignificand << (SINGLE_NUM_SIGNIFICAND_BITS - HALF_NUM_SIGNIFICAND_BITS); - } - uSingleSign = uHalfSign; - - - // Shift the three parts of the single precision into place - const uint32_t uSinglePrecision = uSingleSignificand | - (uSingleBiasedExponent << SINGLE_EXPONENT_SHIFT) | - (uSingleSign << SINGLE_SIGN_SHIFT); - - return CopyUint32ToFloat(uSinglePrecision); -} - - -// Public function; see ieee754.h -double IEEE754_HalfToDouble(uint16_t uHalfPrecision) -{ - // Pull out the three parts of the half-precision float - const uint16_t uHalfSignificand = uHalfPrecision & HALF_SIGNIFICAND_MASK; - const int16_t nHalfUnBiasedExponent = ((uHalfPrecision & HALF_EXPONENT_MASK) >> HALF_EXPONENT_SHIFT) - HALF_EXPONENT_BIAS; - const uint16_t uHalfSign = (uHalfPrecision & HALF_SIGN_MASK) >> HALF_SIGN_SHIFT; - - - // Make the three parts of hte single-precision number - uint64_t uDoubleSignificand, uDoubleSign, uDoubleBiasedExponent; - if(nHalfUnBiasedExponent == HALF_EXPONENT_ZERO) { - // 0 or subnormal - uDoubleBiasedExponent = DOUBLE_EXPONENT_ZERO + DOUBLE_EXPONENT_BIAS; - if(uHalfSignificand) { - // Subnormal case - uDoubleBiasedExponent = -HALF_EXPONENT_BIAS + DOUBLE_EXPONENT_BIAS +1; - // A half-precision subnormal can always be converted to a normal double-precision float because the ranges line up - uDoubleSignificand = uHalfSignificand; - // Shift bits from right of the decimal to left, reducing the exponent by 1 each time - do { - uDoubleSignificand <<= 1; - uDoubleBiasedExponent--; - } while ((uDoubleSignificand & 0x400) == 0); - uDoubleSignificand &= HALF_SIGNIFICAND_MASK; - uDoubleSignificand <<= (DOUBLE_NUM_SIGNIFICAND_BITS - HALF_NUM_SIGNIFICAND_BITS); - } else { - // Just zero - uDoubleSignificand = 0; - } - } else if(nHalfUnBiasedExponent == HALF_EXPONENT_INF_OR_NAN) { - // NaN or Inifinity - uDoubleBiasedExponent = DOUBLE_EXPONENT_INF_OR_NAN + DOUBLE_EXPONENT_BIAS; - if(uHalfSignificand) { - // NaN - // First preserve the NaN payload from half to single - uDoubleSignificand = uHalfSignificand & ~HALF_QUIET_NAN_BIT; - if(uHalfSignificand & HALF_QUIET_NAN_BIT) { - // Next, set qNaN if needed since half qNaN bit is not copied above - uDoubleSignificand |= DOUBLE_QUIET_NAN_BIT; - } - } else { - // Infinity - uDoubleSignificand = 0; - } - } else { - // Normal number - uDoubleBiasedExponent = nHalfUnBiasedExponent + DOUBLE_EXPONENT_BIAS; - uDoubleSignificand = (uint64_t)uHalfSignificand << (DOUBLE_NUM_SIGNIFICAND_BITS - HALF_NUM_SIGNIFICAND_BITS); - } - uDoubleSign = uHalfSign; - - - // Shift the 3 parts into place as a double-precision - const uint64_t uDouble = uDoubleSignificand | - (uDoubleBiasedExponent << DOUBLE_EXPONENT_SHIFT) | - (uDoubleSign << DOUBLE_SIGN_SHIFT); - return CopyUint64ToDouble(uDouble); -} - - -// Public function; see ieee754.h -IEEE754_union IEEE754_FloatToSmallest(float f) -{ - IEEE754_union result; - - // Pull the neeed two parts out of the single-precision float - const uint32_t uSingle = CopyFloatToUint32(f); - const int32_t nSingleExponent = ((uSingle & SINGLE_EXPONENT_MASK) >> SINGLE_EXPONENT_SHIFT) - SINGLE_EXPONENT_BIAS; - const uint32_t uSingleSignificand = uSingle & SINGLE_SIGNIFICAND_MASK; - - // Bit mask that is the significand bits that would be lost when converting - // from single-precision to half-precision - const uint64_t uDroppedSingleBits = SINGLE_SIGNIFICAND_MASK >> HALF_NUM_SIGNIFICAND_BITS; - - // Optimizer will re organize so there is only one call to IEEE754_FloatToHalf() - if(uSingle == 0) { - // Value is 0.0000, not a a subnormal - result.uSize = IEEE754_UNION_IS_HALF; - result.uValue = IEEE754_FloatToHalf(f); - } else if(nSingleExponent == SINGLE_EXPONENT_INF_OR_NAN) { - // NaN, +/- infinity - result.uSize = IEEE754_UNION_IS_HALF; - result.uValue = IEEE754_FloatToHalf(f); - } else if((nSingleExponent >= HALF_EXPONENT_MIN) && nSingleExponent <= HALF_EXPONENT_MAX && (!(uSingleSignificand & uDroppedSingleBits))) { - // Normal number in exponent range and precision won't be lost - result.uSize = IEEE754_UNION_IS_HALF; - result.uValue = IEEE754_FloatToHalf(f); - } else { - // Subnormal, exponent out of range, or precision will be lost - result.uSize = IEEE754_UNION_IS_SINGLE; - result.uValue = uSingle; - } - - return result; -} - -// Public function; see ieee754.h -IEEE754_union IEEE754_DoubleToSmallestInternal(double d, int bAllowHalfPrecision) -{ - IEEE754_union result; - - // Pull the needed two parts out of the double-precision float - const uint64_t uDouble = CopyDoubleToUint64(d); - const int64_t nDoubleExponent = ((uDouble & DOUBLE_EXPONENT_MASK) >> DOUBLE_EXPONENT_SHIFT) - DOUBLE_EXPONENT_BIAS; - const uint64_t uDoubleSignificand = uDouble & DOUBLE_SIGNIFICAND_MASK; - - // Masks to check whether dropped significand bits are zero or not - const uint64_t uDroppedDoubleBits = DOUBLE_SIGNIFICAND_MASK >> HALF_NUM_SIGNIFICAND_BITS; - const uint64_t uDroppedSingleBits = DOUBLE_SIGNIFICAND_MASK >> SINGLE_NUM_SIGNIFICAND_BITS; - - // The various cases - if(d == 0.0) { // Take care of positive and negative zero - // Value is 0.0000, not a a subnormal - result.uSize = IEEE754_UNION_IS_HALF; - result.uValue = IEEE754_DoubleToHalf(d); - } else if(nDoubleExponent == DOUBLE_EXPONENT_INF_OR_NAN) { - // NaN, +/- infinity - result.uSize = IEEE754_UNION_IS_HALF; - result.uValue = IEEE754_DoubleToHalf(d); - } else if(bAllowHalfPrecision && (nDoubleExponent >= HALF_EXPONENT_MIN) && nDoubleExponent <= HALF_EXPONENT_MAX && (!(uDoubleSignificand & uDroppedDoubleBits))) { - // Can convert to half without precision loss - result.uSize = IEEE754_UNION_IS_HALF; - result.uValue = IEEE754_DoubleToHalf(d); - } else if((nDoubleExponent >= SINGLE_EXPONENT_MIN) && nDoubleExponent <= SINGLE_EXPONENT_MAX && (!(uDoubleSignificand & uDroppedSingleBits))) { - // Can convert to single without precision loss - result.uSize = IEEE754_UNION_IS_SINGLE; - result.uValue = CopyFloatToUint32((float)d); - } else { - // Can't convert without precision loss - result.uSize = IEEE754_UNION_IS_DOUBLE; - result.uValue = uDouble; - } - - return result; -} - diff --git a/components/TARGET_PSA/services/attestation/qcbor/src/ieee754.h b/components/TARGET_PSA/services/attestation/qcbor/src/ieee754.h deleted file mode 100644 index 2530f98..0000000 --- a/components/TARGET_PSA/services/attestation/qcbor/src/ieee754.h +++ /dev/null @@ -1,168 +0,0 @@ -/*============================================================================== - ieee754.c -- floating point conversion between half, double and single precision - - Copyright (c) 2018-2019, Laurence Lundblade. All rights reserved. - - SPDX-License-Identifier: BSD-3-Clause - - See BSD-3-Clause license in README.md - - Created on 7/23/18 - ==============================================================================*/ - -#ifndef ieee754_h -#define ieee754_h - -#include - - - -/* - General comments - - This is a complete in that it handles all conversion cases - including +/- infinity, +/- zero, subnormal numbers, qNaN, sNaN - and NaN payloads. - - This confirms to IEEE 754-2008, but note that this doesn't - specify conversions, just the encodings. - - NaN payloads are preserved with alignment on the LSB. The - qNaN bit is handled differently and explicity copied. It - is always the MSB of the significand. The NaN payload MSBs - (except the qNaN bit) are truncated when going from - double or single to half. - - TODO: what does the C cast do with NaN payloads from - double to single? - - - - */ - -/* - Most simply just explicilty encode the type you want, single or double. - This works easily everywhere since standard C supports both - these types and so does qcbor. This encoder also supports - half precision and there's a few ways to use it to encode - floating point numbers in less space. - - Without losing precision, you can encode a single or double - such that the special values of 0, NaN and Infinity encode - as half-precision. This CBOR decodoer and most others - should handle this properly. - - If you don't mind losing precision, then you can use half-precision. - One way to do this is to set up your environment to use - ___fp_16. Some compilers and CPUs support it even though it is not - standard C. What is nice about this is that your program - will use less memory and floating point operations like - multiplying, adding and such will be faster. - - Another way to make use of half-precision is to represent - the values in your program as single or double, but encode - them in CBOR as half-precision. This cuts the size - of the encoded messages by 2 or 4, but doesn't reduce - memory needs or speed because you are still using - single or double in your code. - - - encode: - - float as float - - double as double - - half as half - - float as half_precision, for environments that don't support a half-precision type - - double as half_precision, for environments that don't support a half-precision type - - float with NaN, Infinity and 0 as half - - double with NaN, Infinity and 0 as half - - - - - */ - - - -/* - Convert single precision float to half-precision float. - Precision and NaN payload bits will be lost. Too large - values will round up to infinity and too small to zero. - */ -uint16_t IEEE754_FloatToHalf(float f); - - -/* - Convert half precision float to single precision float. - This is a loss-less conversion. - */ -float IEEE754_HalfToFloat(uint16_t uHalfPrecision); - - -/* - Convert double precision float to half-precision float. - Precision and NaN payload bits will be lost. Too large - values will round up to infinity and too small to zero. - */ -uint16_t IEEE754_DoubleToHalf(double d); - - -/* - Convert half precision float to double precision float. - This is a loss-less conversion. - */ -double IEEE754_HalfToDouble(uint16_t uHalfPrecision); - - - -// Both tags the value and gives the size -#define IEEE754_UNION_IS_HALF 2 -#define IEEE754_UNION_IS_SINGLE 4 -#define IEEE754_UNION_IS_DOUBLE 8 - -typedef struct { - uint8_t uSize; // One of IEEE754_IS_xxxx - uint64_t uValue; -} IEEE754_union; - - -/* - Converts double-precision to single-precision or half-precision if possible without - loss of precisions. If not, leaves it as a double. Only converts to single-precision - unless bAllowHalfPrecision is set. - */ -IEEE754_union IEEE754_DoubleToSmallestInternal(double d, int bAllowHalfPrecision); - -/* - Converts double-precision to single-precision if possible without - loss of precision. If not, leaves it as a double. - */ -static inline IEEE754_union IEEE754_DoubleToSmall(double d) -{ - return IEEE754_DoubleToSmallestInternal(d, 0); -} - - -/* - Converts double-precision to single-precision or half-precision if possible without - loss of precisions. If not, leaves it as a double. - */ -static inline IEEE754_union IEEE754_DoubleToSmallest(double d) -{ - return IEEE754_DoubleToSmallestInternal(d, 1); -} - -/* - Converts single-precision to half-precision if possible without - loss of precision. If not leaves as single-precision. - */ -IEEE754_union IEEE754_FloatToSmallest(float f); - - -#endif /* ieee754_h */ - - - - - - - diff --git a/components/TARGET_PSA/services/attestation/qcbor/src/qcbor_decode.c b/components/TARGET_PSA/services/attestation/qcbor/src/qcbor_decode.c deleted file mode 100644 index 2cfb130..0000000 --- a/components/TARGET_PSA/services/attestation/qcbor/src/qcbor_decode.c +++ /dev/null @@ -1,1320 +0,0 @@ -/*============================================================================== - Copyright (c) 2016-2018, The Linux Foundation. - Copyright (c) 2018-2019, Laurence Lundblade. - All rights reserved. - SPDX-License-Identifier: BSD-3-Clause - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of The Linux Foundation nor the names of its - contributors, nor the name "Laurence Lundblade" may be used to - endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED -WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT -ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS -BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE -OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN -IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ==============================================================================*/ - -/*=================================================================================== - FILE: qcbor_decode.c - - DESCRIPTION: This file contains the implementation of QCBOR. - - EDIT HISTORY FOR FILE: - - This section contains comments describing changes made to the module. - Notice that changes are listed in reverse chronological order. - - when who what, where, why - -------- ---- --------------------------------------------------- - 01/10/19 llundblade Clever type and argument decoder is 250 bytes smaller - 11/9/18 llundblade Error codes are now enums. - 11/2/18 llundblade Simplify float decoding and align with preferred - float encoding - 10/31/18 llundblade Switch to one license that is almost BSD-3. - 10/28/18 llundblade Reworked tag decoding - 10/15/18 llundblade Indefinite length maps and arrays supported - 10/8/18 llundblade Indefinite length strings supported - 02/04/17 llundbla Work on CPUs that don's require pointer alignment - by making use of changes in UsefulBuf - 03/01/17 llundbla More data types; decoding improvements and fixes - 11/13/16 llundbla Integrate most TZ changes back into github version. - 09/30/16 gkanike Porting to TZ. - 03/15/16 llundbla Initial Version. - - =====================================================================================*/ - -#include "qcbor.h" -#include "ieee754.h" - - -/* - This casts away the const-ness of a pointer, usually so it can be - freed or realloced. - */ -#define UNCONST_POINTER(ptr) ((void *)(ptr)) - - -/* - Collection of functions to track the map/array nesting for decoding - */ - -inline static int IsMapOrArray(uint8_t uDataType) -{ - return uDataType == QCBOR_TYPE_MAP || uDataType == QCBOR_TYPE_ARRAY; -} - -inline static int DecodeNesting_IsNested(const QCBORDecodeNesting *pNesting) -{ - return pNesting->pCurrent != &(pNesting->pMapsAndArrays[0]); -} - -inline static int DecodeNesting_IsIndefiniteLength(const QCBORDecodeNesting *pNesting) -{ - return pNesting->pCurrent->uCount == UINT16_MAX; -} - -inline static uint8_t DecodeNesting_GetLevel(QCBORDecodeNesting *pNesting) -{ - return pNesting->pCurrent - &(pNesting->pMapsAndArrays[0]); -} - -inline static int DecodeNesting_TypeIsMap(const QCBORDecodeNesting *pNesting) -{ - if(!DecodeNesting_IsNested(pNesting)) { - return 0; - } - - return CBOR_MAJOR_TYPE_MAP == pNesting->pCurrent->uMajorType; -} - -// Process a break. This will either ascend the nesting or error out -inline static QCBORError DecodeNesting_BreakAscend(QCBORDecodeNesting *pNesting) -{ - // breaks must always occur when there is nesting - if(!DecodeNesting_IsNested(pNesting)) { - return QCBOR_ERR_BAD_BREAK; - } - - // breaks can only occur when the map/array is indefinite length - if(!DecodeNesting_IsIndefiniteLength(pNesting)) { - return QCBOR_ERR_BAD_BREAK; - } - - // if all OK, the break reduces the level of nesting - pNesting->pCurrent--; - - return QCBOR_SUCCESS; -} - -// Called on every single item except breaks including the opening of a map/array -inline static void DecodeNesting_DecrementCount(QCBORDecodeNesting *pNesting) -{ - if(!DecodeNesting_IsNested(pNesting)) { - // at top level where there is no tracking - return; - } - - if(DecodeNesting_IsIndefiniteLength(pNesting)) { - // There is no count for indefinite length arrays/maps - return; - } - - // Decrement the count of items in this array/map - pNesting->pCurrent->uCount--; - - // Pop up nesting levels if the counts at the levels are zero - while(DecodeNesting_IsNested(pNesting) && 0 == pNesting->pCurrent->uCount) { - pNesting->pCurrent--; - if(!DecodeNesting_IsIndefiniteLength(pNesting)) { - pNesting->pCurrent->uCount--; - } - } -} - -// Called on every map/array -inline static QCBORError DecodeNesting_Descend(QCBORDecodeNesting *pNesting, QCBORItem *pItem) -{ - QCBORError nReturn = QCBOR_SUCCESS; - - if(pItem->val.uCount == 0) { - // Nothing to do for empty definite lenth arrays. They are just are - // effectively the same as an item that is not a map or array - goto Done; - // Empty indefinite length maps and arrays are handled elsewhere - } - - // Error out if arrays is too long to handle - if(pItem->val.uCount != UINT16_MAX && pItem->val.uCount > QCBOR_MAX_ITEMS_IN_ARRAY) { - nReturn = QCBOR_ERR_ARRAY_TOO_LONG; - goto Done; - } - - // Error out if nesting is too deep - if(pNesting->pCurrent >= &(pNesting->pMapsAndArrays[QCBOR_MAX_ARRAY_NESTING])) { - nReturn = QCBOR_ERR_ARRAY_NESTING_TOO_DEEP; - goto Done; - } - - // The actual descend - pNesting->pCurrent++; - - // Record a few details for this nesting level - pNesting->pCurrent->uMajorType = pItem->uDataType; - pNesting->pCurrent->uCount = pItem->val.uCount; - -Done: - return nReturn;; -} - -inline static void DecodeNesting_Init(QCBORDecodeNesting *pNesting) -{ - pNesting->pCurrent = &(pNesting->pMapsAndArrays[0]); -} - - - -/* - This list of built-in tags. Only add tags here that are - clearly established and useful. Once a tag is added here - it can't be taken out as that would break backwards compatibility. - There are only 48 slots available forever. - */ -static const uint16_t spBuiltInTagMap[] = { - CBOR_TAG_DATE_STRING, // See TAG_MAPPER_FIRST_FOUR - CBOR_TAG_DATE_EPOCH, // See TAG_MAPPER_FIRST_FOUR - CBOR_TAG_POS_BIGNUM, // See TAG_MAPPER_FIRST_FOUR - CBOR_TAG_NEG_BIGNUM, // See TAG_MAPPER_FIRST_FOUR - CBOR_TAG_FRACTION, - CBOR_TAG_BIGFLOAT, - CBOR_TAG_COSE_ENCRYPTO, - CBOR_TAG_COSE_MAC0, - CBOR_TAG_COSE_SIGN1, - CBOR_TAG_ENC_AS_B64URL, - CBOR_TAG_ENC_AS_B64, - CBOR_TAG_ENC_AS_B16, - CBOR_TAG_CBOR, - CBOR_TAG_URI, - CBOR_TAG_B64URL, - CBOR_TAG_B64, - CBOR_TAG_REGEX, - CBOR_TAG_MIME, - CBOR_TAG_BIN_UUID, - CBOR_TAG_CWT, - CBOR_TAG_ENCRYPT, - CBOR_TAG_MAC, - CBOR_TAG_SIGN, - CBOR_TAG_GEO_COORD, - CBOR_TAG_CBOR_MAGIC -}; - -// This is used in a bit of cleverness in GetNext_TaggedItem() to -// keep code size down and switch for the internal processing of -// these types. This will break if the first four items in -// spBuiltInTagMap don't have values 0,1,2,3. That is the -// mapping is 0 to 0, 1 to 1, 2 to 2 and 3 to 3. -#define QCBOR_TAGFLAG_DATE_STRING (0x01LL << CBOR_TAG_DATE_STRING) -#define QCBOR_TAGFLAG_DATE_EPOCH (0x01LL << CBOR_TAG_DATE_EPOCH) -#define QCBOR_TAGFLAG_POS_BIGNUM (0x01LL << CBOR_TAG_POS_BIGNUM) -#define QCBOR_TAGFLAG_NEG_BIGNUM (0x01LL << CBOR_TAG_NEG_BIGNUM) - -#define TAG_MAPPER_FIRST_FOUR (QCBOR_TAGFLAG_DATE_STRING |\ - QCBOR_TAGFLAG_DATE_EPOCH |\ - QCBOR_TAGFLAG_POS_BIGNUM |\ - QCBOR_TAGFLAG_NEG_BIGNUM) - -#define TAG_MAPPER_TOTAL_TAG_BITS 64 // Number of bits in a uint64_t -#define TAG_MAPPER_CUSTOM_TAGS_BASE_INDEX (TAG_MAPPER_TOTAL_TAG_BITS - QCBOR_MAX_CUSTOM_TAGS) // 48 -#define TAG_MAPPER_MAX_SIZE_BUILT_IN_TAGS (TAG_MAPPER_TOTAL_TAG_BITS - QCBOR_MAX_CUSTOM_TAGS ) // 48 - -static inline int TagMapper_LookupBuiltIn(uint64_t uTag) -{ - if(sizeof(spBuiltInTagMap)/sizeof(uint16_t) > TAG_MAPPER_MAX_SIZE_BUILT_IN_TAGS) { - // This is a cross-check to make sure the above array doesn't - // accidentally get made too big. - // In normal conditions the above test should optimize out - // as all the values are known at compile time. - return -1; - } - - if(uTag > UINT16_MAX) { - // This tag map works only on 16-bit tags - return -1; - } - - for(int nTagBitIndex = 0; nTagBitIndex < (int)(sizeof(spBuiltInTagMap)/sizeof(uint16_t)); nTagBitIndex++) { - if(spBuiltInTagMap[nTagBitIndex] == uTag) { - return nTagBitIndex; - } - } - return -1; // Indicates no match -} - -static inline int TagMapper_LookupCallerConfigured(const QCBORTagListIn *pCallerConfiguredTagMap, uint64_t uTag) -{ - for(int nTagBitIndex = 0; nTagBitIndex < pCallerConfiguredTagMap->uNumTags; nTagBitIndex++) { - if(pCallerConfiguredTagMap->puTags[nTagBitIndex] == uTag) { - return nTagBitIndex + TAG_MAPPER_CUSTOM_TAGS_BASE_INDEX; - } - } - - return -1; // Indicates no match -} - -/* - Find the tag bit index for a given tag value, or error out - - This and the above functions could probably be optimized and made - clearer and neater. - */ -static QCBORError TagMapper_Lookup(const QCBORTagListIn *pCallerConfiguredTagMap, uint64_t uTag, uint8_t *puTagBitIndex) -{ - int nTagBitIndex = TagMapper_LookupBuiltIn(uTag); - if(nTagBitIndex >= 0) { - // Cast is safe because TagMapper_LookupBuiltIn never returns > 47 - *puTagBitIndex = (uint8_t)nTagBitIndex; - return QCBOR_SUCCESS; - } - - if(pCallerConfiguredTagMap) { - if(pCallerConfiguredTagMap->uNumTags > QCBOR_MAX_CUSTOM_TAGS) { - return QCBOR_ERR_TOO_MANY_TAGS; - } - nTagBitIndex = TagMapper_LookupCallerConfigured(pCallerConfiguredTagMap, uTag); - if(nTagBitIndex >= 0) { - // Cast is safe because TagMapper_LookupBuiltIn never returns > 63 - - *puTagBitIndex = (uint8_t)nTagBitIndex; - return QCBOR_SUCCESS; - } - } - - return QCBOR_ERR_BAD_OPT_TAG; -} - - - - -/* - Public function, see header file - */ -void QCBORDecode_Init(QCBORDecodeContext *me, UsefulBufC EncodedCBOR, QCBORDecodeMode nDecodeMode) -{ - memset(me, 0, sizeof(QCBORDecodeContext)); - UsefulInputBuf_Init(&(me->InBuf), EncodedCBOR); - // Don't bother with error check on decode mode. If a bad value is passed it will just act as - // if the default normal mode of 0 was set. - me->uDecodeMode = nDecodeMode; - DecodeNesting_Init(&(me->nesting)); -} - - -/* - Public function, see header file - */ -void QCBORDecode_SetUpAllocator(QCBORDecodeContext *pCtx, const QCBORStringAllocator *pAllocator, bool bAllocAll) -{ - pCtx->pStringAllocator = (void *)pAllocator; - pCtx->bStringAllocateAll = bAllocAll; -} - -void QCBORDecode_SetCallerConfiguredTagList(QCBORDecodeContext *me, const QCBORTagListIn *pTagList) -{ - me->pCallerConfiguredTagList = pTagList; -} - - -/* - This decodes the fundamental part of a CBOR data item, the type and number - - This is the Counterpart to InsertEncodedTypeAndNumber(). - - This does the network->host byte order conversion. The conversion here - also results in the conversion for floats in addition to that for - lengths, tags and integer values. - - This returns: - pnMajorType -- the major type for the item - puNumber -- the "number" which is used a the value for integers, tags and floats and length for strings and arrays - puAdditionalInfo -- Pass this along to know what kind of float or if length is indefinite - - */ -inline static QCBORError DecodeTypeAndNumber(UsefulInputBuf *pUInBuf, - int *pnMajorType, - uint64_t *puArgument, - uint8_t *puAdditionalInfo) -{ - QCBORError nReturn; - - // Get the initial byte that every CBOR data item has - const uint8_t uInitialByte = UsefulInputBuf_GetByte(pUInBuf); - - // Break down the initial byte - const uint8_t uTmpMajorType = uInitialByte >> 5; - const uint8_t uAdditionalInfo = uInitialByte & 0x1f; - - // Where the number or argument accumulates - uint64_t uArgument; - - if(uAdditionalInfo >= LEN_IS_ONE_BYTE && uAdditionalInfo <= LEN_IS_EIGHT_BYTES) { - // Need to get 1,2,4 or 8 additional argument bytes - // Map LEN_IS_ONE_BYTE.. LEN_IS_EIGHT_BYTES to actual length - static const uint8_t aIterate[] = {1,2,4,8}; - - // Loop getting all the bytes in the argument - uArgument = 0; - for(int i = aIterate[uAdditionalInfo - LEN_IS_ONE_BYTE]; i; i--) { - // This shift and add gives the endian conversion - uArgument = (uArgument << 8) + UsefulInputBuf_GetByte(pUInBuf); - } - } else if(uAdditionalInfo >= ADDINFO_RESERVED1 && uAdditionalInfo <= ADDINFO_RESERVED3) { - // The reserved and thus-far unused additional info values - nReturn = QCBOR_ERR_UNSUPPORTED; - goto Done; - } else { - // Less than 24, additional info is argument or 31, an indefinite length - // No more bytes to get - uArgument = uAdditionalInfo; - } - - if(UsefulInputBuf_GetError(pUInBuf)) { - nReturn = QCBOR_ERR_HIT_END; - goto Done; - } - - // All successful if we got here. - nReturn = QCBOR_SUCCESS; - *pnMajorType = uTmpMajorType; - *puArgument = uArgument; - *puAdditionalInfo = uAdditionalInfo; - -Done: - return nReturn; -} - -/* - CBOR doesn't explicitly specify two's compliment for integers but all CPUs - use it these days and the test vectors in the RFC are so. All integers in the CBOR - structure are positive and the major type indicates positive or negative. - CBOR can express positive integers up to 2^x - 1 where x is the number of bits - and negative integers down to 2^x. Note that negative numbers can be one - more away from zero than positive. - Stdint, as far as I can tell, uses two's compliment to represent - negative integers. - - See http://www.unix.org/whitepapers/64bit.html for reasons int isn't - used here in any way including in the interface - */ -inline static QCBORError DecodeInteger(int nMajorType, uint64_t uNumber, QCBORItem *pDecodedItem) -{ - // Stack usage: int/ptr 1 -- 8 - QCBORError nReturn = QCBOR_SUCCESS; - - if(nMajorType == CBOR_MAJOR_TYPE_POSITIVE_INT) { - if (uNumber <= INT64_MAX) { - pDecodedItem->val.int64 = (int64_t)uNumber; - pDecodedItem->uDataType = QCBOR_TYPE_INT64; - - } else { - pDecodedItem->val.uint64 = uNumber; - pDecodedItem->uDataType = QCBOR_TYPE_UINT64; - - } - } else { - if(uNumber <= INT64_MAX) { - pDecodedItem->val.int64 = -uNumber-1; - pDecodedItem->uDataType = QCBOR_TYPE_INT64; - - } else { - // C can't represent a negative integer in this range - // so it is an error. todo -- test this condition - nReturn = QCBOR_ERR_INT_OVERFLOW; - } - } - - return nReturn; -} - -// Make sure #define value line up as DecodeSimple counts on this. -#if QCBOR_TYPE_FALSE != CBOR_SIMPLEV_FALSE -#error QCBOR_TYPE_FALSE macro value wrong -#endif - -#if QCBOR_TYPE_TRUE != CBOR_SIMPLEV_TRUE -#error QCBOR_TYPE_TRUE macro value wrong -#endif - -#if QCBOR_TYPE_NULL != CBOR_SIMPLEV_NULL -#error QCBOR_TYPE_NULL macro value wrong -#endif - -#if QCBOR_TYPE_UNDEF != CBOR_SIMPLEV_UNDEF -#error QCBOR_TYPE_UNDEF macro value wrong -#endif - -#if QCBOR_TYPE_BREAK != CBOR_SIMPLE_BREAK -#error QCBOR_TYPE_BREAK macro value wrong -#endif - -#if QCBOR_TYPE_DOUBLE != DOUBLE_PREC_FLOAT -#error QCBOR_TYPE_DOUBLE macro value wrong -#endif - -#if QCBOR_TYPE_FLOAT != SINGLE_PREC_FLOAT -#error QCBOR_TYPE_FLOAT macro value wrong -#endif - -/* - Decode true, false, floats, break... - */ - -inline static QCBORError DecodeSimple(uint8_t uAdditionalInfo, uint64_t uNumber, QCBORItem *pDecodedItem) -{ - // Stack usage: 0 - QCBORError nReturn = QCBOR_SUCCESS; - - // uAdditionalInfo is 5 bits from the initial byte - // compile time checks above make sure uAdditionalInfo values line up with uDataType values - pDecodedItem->uDataType = uAdditionalInfo; - - switch(uAdditionalInfo) { - case ADDINFO_RESERVED1: // 28 - case ADDINFO_RESERVED2: // 29 - case ADDINFO_RESERVED3: // 30 - nReturn = QCBOR_ERR_UNSUPPORTED; - break; - - case HALF_PREC_FLOAT: - pDecodedItem->val.dfnum = IEEE754_HalfToDouble((uint16_t)uNumber); - pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE; - break; - case SINGLE_PREC_FLOAT: - pDecodedItem->val.dfnum = (double)UsefulBufUtil_CopyUint32ToFloat((uint32_t)uNumber); - pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE; - break; - case DOUBLE_PREC_FLOAT: - pDecodedItem->val.dfnum = UsefulBufUtil_CopyUint64ToDouble(uNumber); - pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE; - break; - - case CBOR_SIMPLEV_FALSE: // 20 - case CBOR_SIMPLEV_TRUE: // 21 - case CBOR_SIMPLEV_NULL: // 22 - case CBOR_SIMPLEV_UNDEF: // 23 - case CBOR_SIMPLE_BREAK: // 31 - break; // nothing to do - - case CBOR_SIMPLEV_ONEBYTE: // 24 - if(uNumber <= CBOR_SIMPLE_BREAK) { - // This takes out f8 00 ... f8 1f which should be encoded as e0 … f7 - nReturn = QCBOR_ERR_INVALID_CBOR; - goto Done; - } - /* FALLTHROUGH */ - // fall through intentionally - - default: // 0-19 - pDecodedItem->uDataType = QCBOR_TYPE_UKNOWN_SIMPLE; - // DecodeTypeAndNumber will make uNumber equal to uAdditionalInfo when uAdditionalInfo is < 24 - // This cast is safe because the 2, 4 and 8 byte lengths of uNumber are in the double/float cases above - pDecodedItem->val.uSimple = (uint8_t)uNumber; - break; - } - -Done: - return nReturn; -} - - - -/* - Decode text and byte strings. Call the string allocator if asked to. - */ -inline static QCBORError DecodeBytes(const QCBORStringAllocator *pAlloc, int nMajorType, uint64_t uStrLen, UsefulInputBuf *pUInBuf, QCBORItem *pDecodedItem) -{ - // Stack usage: UsefulBuf 2, int/ptr 1 40 - QCBORError nReturn = QCBOR_SUCCESS; - - const UsefulBufC Bytes = UsefulInputBuf_GetUsefulBuf(pUInBuf, uStrLen); - if(UsefulBuf_IsNULLC(Bytes)) { - // Failed to get the bytes for this string item - nReturn = QCBOR_ERR_HIT_END; - goto Done; - } - - if(pAlloc) { - // We are asked to use string allocator to make a copy - UsefulBuf NewMem = pAlloc->fAllocate(pAlloc->pAllocaterContext, NULL, uStrLen); - if(UsefulBuf_IsNULL(NewMem)) { - nReturn = QCBOR_ERR_STRING_ALLOCATE; - goto Done; - } - pDecodedItem->val.string = UsefulBuf_Copy(NewMem, Bytes); - } else { - // Normal case with no string allocator - pDecodedItem->val.string = Bytes; - } - pDecodedItem->uDataType = (nMajorType == CBOR_MAJOR_TYPE_BYTE_STRING) ? QCBOR_TYPE_BYTE_STRING : QCBOR_TYPE_TEXT_STRING; - -Done: - return nReturn; -} - - -/* - Mostly just assign the right data type for the date string. - */ -inline static QCBORError DecodeDateString(QCBORItem *pDecodedItem) -{ - // Stack Use: UsefulBuf 1 16 - if(pDecodedItem->uDataType != QCBOR_TYPE_TEXT_STRING) { - return QCBOR_ERR_BAD_OPT_TAG; - } - - const UsefulBufC Temp = pDecodedItem->val.string; - pDecodedItem->val.dateString = Temp; - pDecodedItem->uDataType = QCBOR_TYPE_DATE_STRING; - return QCBOR_SUCCESS; -} - - -/* - Mostly just assign the right data type for the bignum. - */ -inline static QCBORError DecodeBigNum(QCBORItem *pDecodedItem) -{ - // Stack Use: UsefulBuf 1 -- 16 - if(pDecodedItem->uDataType != QCBOR_TYPE_BYTE_STRING) { - return QCBOR_ERR_BAD_OPT_TAG; - } - const UsefulBufC Temp = pDecodedItem->val.string; - pDecodedItem->val.bigNum = Temp; - pDecodedItem->uDataType = pDecodedItem->uTagBits & QCBOR_TAGFLAG_POS_BIGNUM ? QCBOR_TYPE_POSBIGNUM : QCBOR_TYPE_NEGBIGNUM; - return QCBOR_SUCCESS; -} - - -/* - The epoch formatted date. Turns lots of different forms of encoding date into uniform one - */ -static int DecodeDateEpoch(QCBORItem *pDecodedItem) -{ - // Stack usage: 1 - QCBORError nReturn = QCBOR_SUCCESS; - - pDecodedItem->val.epochDate.fSecondsFraction = 0; - - switch (pDecodedItem->uDataType) { - - case QCBOR_TYPE_INT64: - pDecodedItem->val.epochDate.nSeconds = pDecodedItem->val.int64; - break; - - case QCBOR_TYPE_UINT64: - if(pDecodedItem->val.uint64 > INT64_MAX) { - nReturn = QCBOR_ERR_DATE_OVERFLOW; - goto Done; - } - pDecodedItem->val.epochDate.nSeconds = pDecodedItem->val.uint64; - break; - - case QCBOR_TYPE_DOUBLE: - { - const double d = pDecodedItem->val.dfnum; - if(d > INT64_MAX) { - nReturn = QCBOR_ERR_DATE_OVERFLOW; - goto Done; - } - pDecodedItem->val.epochDate.nSeconds = d; // Float to integer conversion happening here. - pDecodedItem->val.epochDate.fSecondsFraction = d - pDecodedItem->val.epochDate.nSeconds; - } - break; - - default: - nReturn = QCBOR_ERR_BAD_OPT_TAG; - goto Done; - } - pDecodedItem->uDataType = QCBOR_TYPE_DATE_EPOCH; - -Done: - return nReturn; -} - - - - -// Make sure the constants align as this is assumed by the GetAnItem() implementation -#if QCBOR_TYPE_ARRAY != CBOR_MAJOR_TYPE_ARRAY -#error QCBOR_TYPE_ARRAY value not lined up with major type -#endif -#if QCBOR_TYPE_MAP != CBOR_MAJOR_TYPE_MAP -#error QCBOR_TYPE_MAP value not lined up with major type -#endif - -/* - This gets a single data item and decodes it including preceding optional tagging. This does not - deal with arrays and maps and nesting except to decode the data item introducing them. Arrays and - maps are handled at the next level up in GetNext(). - - Errors detected here include: an array that is too long to decode, hit end of buffer unexpectedly, - a few forms of invalid encoded CBOR - */ -static QCBORError GetNext_Item(UsefulInputBuf *pUInBuf, QCBORItem *pDecodedItem, const QCBORStringAllocator *pAlloc) -{ - // Stack usage: int/ptr 3 -- 24 - QCBORError nReturn; - - // Get the major type and the number. Number could be length of more bytes or the value depending on the major type - // nAdditionalInfo is an encoding of the length of the uNumber and is needed to decode floats and doubles - int uMajorType; - uint64_t uNumber; - uint8_t uAdditionalInfo; - - nReturn = DecodeTypeAndNumber(pUInBuf, &uMajorType, &uNumber, &uAdditionalInfo); - - // Error out here if we got into trouble on the type and number. - // The code after this will not work if the type and number is not good. - if(nReturn) - goto Done; - - memset(pDecodedItem, 0, sizeof(QCBORItem)); - - // At this point the major type and the value are valid. We've got the type and the number that - // starts every CBOR data item. - switch (uMajorType) { - case CBOR_MAJOR_TYPE_POSITIVE_INT: // Major type 0 - case CBOR_MAJOR_TYPE_NEGATIVE_INT: // Major type 1 - nReturn = DecodeInteger(uMajorType, uNumber, pDecodedItem); - break; - - case CBOR_MAJOR_TYPE_BYTE_STRING: // Major type 2 - case CBOR_MAJOR_TYPE_TEXT_STRING: // Major type 3 - if(uAdditionalInfo == LEN_IS_INDEFINITE) { - pDecodedItem->uDataType = (uMajorType == CBOR_MAJOR_TYPE_BYTE_STRING) ? QCBOR_TYPE_BYTE_STRING : QCBOR_TYPE_TEXT_STRING; - pDecodedItem->val.string = (UsefulBufC){NULL, SIZE_MAX}; - } else { - nReturn = DecodeBytes(pAlloc, uMajorType, uNumber, pUInBuf, pDecodedItem); - } - break; - - case CBOR_MAJOR_TYPE_ARRAY: // Major type 4 - case CBOR_MAJOR_TYPE_MAP: // Major type 5 - // Record the number of items in the array or map - if(uNumber > QCBOR_MAX_ITEMS_IN_ARRAY) { - nReturn = QCBOR_ERR_ARRAY_TOO_LONG; - goto Done; - } - if(uAdditionalInfo == LEN_IS_INDEFINITE) { - pDecodedItem->val.uCount = UINT16_MAX; // Indicate indefinite length - } else { - pDecodedItem->val.uCount = (uint16_t)uNumber; // type conversion OK because of check above - } - pDecodedItem->uDataType = uMajorType; // C preproc #if above makes sure constants align - break; - - case CBOR_MAJOR_TYPE_OPTIONAL: // Major type 6, optional prepended tags - pDecodedItem->val.uTagV = uNumber; - pDecodedItem->uDataType = QCBOR_TYPE_OPTTAG; - break; - - case CBOR_MAJOR_TYPE_SIMPLE: // Major type 7, float, double, true, false, null... - nReturn = DecodeSimple(uAdditionalInfo, uNumber, pDecodedItem); - break; - - default: // Should never happen because DecodeTypeAndNumber() should never return > 7 - nReturn = QCBOR_ERR_UNSUPPORTED; - break; - } - -Done: - return nReturn; -} - - - -/* - This layer deals with indefinite length strings. It pulls all the - individual chunk items together into one QCBORItem using the - string allocator. - - Code Reviewers: THIS FUNCTION DOES A LITTLE POINTER MATH - */ -static inline QCBORError GetNext_FullItem(QCBORDecodeContext *me, QCBORItem *pDecodedItem) -{ - // Stack usage; int/ptr 2 UsefulBuf 2 QCBORItem -- 96 - QCBORError nReturn; - QCBORStringAllocator *pAlloc = (QCBORStringAllocator *)me->pStringAllocator; - UsefulBufC FullString = NULLUsefulBufC; - - nReturn = GetNext_Item(&(me->InBuf), pDecodedItem, me->bStringAllocateAll ? pAlloc: NULL); - if(nReturn) { - goto Done; - } - - // To reduce code size by removing support for indefinite length strings, the - // code in this function from here down can be eliminated. Run tests, except - // indefinite length string tests, to be sure all is OK if this is removed. - - // Only do indefinite length processing on strings - if(pDecodedItem->uDataType != QCBOR_TYPE_BYTE_STRING && pDecodedItem->uDataType != QCBOR_TYPE_TEXT_STRING) { - goto Done; // no need to do any work here on non-string types - } - - // Is this a string with an indefinite length? - if(pDecodedItem->val.string.len != SIZE_MAX) { - goto Done; // length is not indefinite, so no work to do here - } - - // Can't do indefinite length strings without a string allocator - if(pAlloc == NULL) { - nReturn = QCBOR_ERR_NO_STRING_ALLOCATOR; - goto Done; - } - - // There is an indefinite length string to work on... - // Track which type of string it is - const uint8_t uStringType = pDecodedItem->uDataType; - - // Loop getting chunk of indefinite string - for(;;) { - // Get item for next chunk - QCBORItem StringChunkItem; - // NULL passed to never string alloc chunk of indefinite length strings - nReturn = GetNext_Item(&(me->InBuf), &StringChunkItem, NULL); - if(nReturn) { - break; // Error getting the next chunk - } - - // See if it is a marker at end of indefinite length string - if(StringChunkItem.uDataType == QCBOR_TYPE_BREAK) { - // String is complete - pDecodedItem->val.string = FullString; - pDecodedItem->uDataAlloc = 1; - break; - } - - // Match data type of chunk to type at beginning. - // Also catches error of other non-string types that don't belong. - if(StringChunkItem.uDataType != uStringType) { - nReturn = QCBOR_ERR_INDEFINITE_STRING_CHUNK; - break; - } - - // Alloc new buffer or expand previously allocated buffer so it can fit - UsefulBuf NewMem = (*pAlloc->fAllocate)(pAlloc->pAllocaterContext, - UNCONST_POINTER(FullString.ptr), - FullString.len + StringChunkItem.val.string.len); - if(UsefulBuf_IsNULL(NewMem)) { - // Allocation of memory for the string failed - nReturn = QCBOR_ERR_STRING_ALLOCATE; - break; - } - - // Copy new string chunk at the end of string so far. - FullString = UsefulBuf_CopyOffset(NewMem, FullString.len, StringChunkItem.val.string); - } - -Done: - if(pAlloc && nReturn && !UsefulBuf_IsNULLC(FullString)) { - // Getting item failed, clean up the allocated memory - (pAlloc->fFree)(pAlloc->pAllocaterContext, UNCONST_POINTER(FullString.ptr)); - } - - return nReturn; -} - - -/* - Returns an error if there was something wrong with the optional item or it couldn't - be handled. - */ -static QCBORError GetNext_TaggedItem(QCBORDecodeContext *me, QCBORItem *pDecodedItem, QCBORTagListOut *pTags) -{ - // Stack usage: int/ptr: 3 -- 24 - QCBORError nReturn; - uint64_t uTagBits = 0; - if(pTags) { - pTags->uNumUsed = 0; - } - - for(;;) { - nReturn = GetNext_FullItem(me, pDecodedItem); - if(nReturn) { - goto Done; // Error out of the loop - } - - if(pDecodedItem->uDataType != QCBOR_TYPE_OPTTAG) { - // Successful exit from loop; maybe got some tags, maybe not - pDecodedItem->uTagBits = uTagBits; - break; - } - - uint8_t uTagBitIndex; - // Tag was mapped, tag was not mapped, error with tag list - switch(TagMapper_Lookup(me->pCallerConfiguredTagList, pDecodedItem->val.uTagV, &uTagBitIndex)) { - - case QCBOR_SUCCESS: - // Successfully mapped the tag - uTagBits |= 0x01ULL << uTagBitIndex; - break; - - case QCBOR_ERR_BAD_OPT_TAG: - // Tag is not recognized. Do nothing - break; - - default: - // Error Condition - goto Done; - } - - if(pTags) { - // Caller wants all tags recorded in the provided buffer - if(pTags->uNumUsed >= pTags->uNumAllocated) { - nReturn = QCBOR_ERR_TOO_MANY_TAGS; - goto Done; - } - pTags->puTags[pTags->uNumUsed] = pDecodedItem->val.uTagV; - pTags->uNumUsed++; - } - } - - switch(pDecodedItem->uTagBits & TAG_MAPPER_FIRST_FOUR) { - case 0: - // No tags at all or none we know about. Nothing to do. - // This is part of the pass-through path of this function - // that will mostly be taken when decoding any item. - break; - - case QCBOR_TAGFLAG_DATE_STRING: - nReturn = DecodeDateString(pDecodedItem); - break; - - case QCBOR_TAGFLAG_DATE_EPOCH: - nReturn = DecodeDateEpoch(pDecodedItem); - break; - - case QCBOR_TAGFLAG_POS_BIGNUM: - case QCBOR_TAGFLAG_NEG_BIGNUM: - nReturn = DecodeBigNum(pDecodedItem); - break; - - default: - // Encountering some mixed up CBOR like something that - // is tagged as both a string and integer date. - nReturn = QCBOR_ERR_BAD_OPT_TAG; - } - -Done: - return nReturn; -} - - -/* - This layer takes care of map entries. It combines the label and data items into one QCBORItem. - */ -static inline QCBORError GetNext_MapEntry(QCBORDecodeContext *me, QCBORItem *pDecodedItem, QCBORTagListOut *pTags) -{ - // Stack use: int/ptr 1, QCBORItem -- 56 - QCBORError nReturn = GetNext_TaggedItem(me, pDecodedItem, pTags); - if(nReturn) - goto Done; - - if(pDecodedItem->uDataType == QCBOR_TYPE_BREAK) { - // Break can't be a map entry - goto Done; - } - - if(me->uDecodeMode != QCBOR_DECODE_MODE_MAP_AS_ARRAY) { - // In a map and caller wants maps decoded, not treated as arrays - - if(DecodeNesting_TypeIsMap(&(me->nesting))) { - // If in a map and the right decoding mode, get the label - - // Get the next item which will be the real data; Item will be the label - QCBORItem LabelItem = *pDecodedItem; - nReturn = GetNext_TaggedItem(me, pDecodedItem, pTags); - if(nReturn) - goto Done; - - pDecodedItem->uLabelAlloc = LabelItem.uDataAlloc; - - if(LabelItem.uDataType == QCBOR_TYPE_TEXT_STRING) { - // strings are always good labels - pDecodedItem->label.string = LabelItem.val.string; - pDecodedItem->uLabelType = QCBOR_TYPE_TEXT_STRING; - } else if (QCBOR_DECODE_MODE_MAP_STRINGS_ONLY == me->uDecodeMode) { - // It's not a string and we only want strings, probably for easy translation to JSON - nReturn = QCBOR_ERR_MAP_LABEL_TYPE; - goto Done; - } else if(LabelItem.uDataType == QCBOR_TYPE_INT64) { - pDecodedItem->label.int64 = LabelItem.val.int64; - pDecodedItem->uLabelType = QCBOR_TYPE_INT64; - } else if(LabelItem.uDataType == QCBOR_TYPE_UINT64) { - pDecodedItem->label.uint64 = LabelItem.val.uint64; - pDecodedItem->uLabelType = QCBOR_TYPE_UINT64; - } else if(LabelItem.uDataType == QCBOR_TYPE_BYTE_STRING) { - pDecodedItem->label.string = LabelItem.val.string; - pDecodedItem->uLabelAlloc = LabelItem.uDataAlloc; - pDecodedItem->uLabelType = QCBOR_TYPE_BYTE_STRING; - } else { - // label is not an int or a string. It is an arrray - // or a float or such and this implementation doesn't handle that. - // Also, tags on labels are ignored. - nReturn = QCBOR_ERR_MAP_LABEL_TYPE; - goto Done; - } - } - } else { - if(pDecodedItem->uDataType == QCBOR_TYPE_MAP) { - // Decoding a map as an array - pDecodedItem->uDataType = QCBOR_TYPE_MAP_AS_ARRAY; - pDecodedItem->val.uCount *= 2; - } - } - -Done: - return nReturn; -} - - -/* - Public function, see header qcbor.h file - */ -QCBORError QCBORDecode_GetNextWithTags(QCBORDecodeContext *me, QCBORItem *pDecodedItem, QCBORTagListOut *pTags) -{ - // Stack ptr/int: 2, QCBORItem : 64 - - // The public entry point for fetching and parsing the next QCBORItem. - // All the CBOR parsing work is here and in subordinate calls. - QCBORError nReturn; - - nReturn = GetNext_MapEntry(me, pDecodedItem, pTags); - if(nReturn) { - goto Done; - } - - // Break ending arrays/maps are always processed at the end of this function. - // They should never show up here. - if(pDecodedItem->uDataType == QCBOR_TYPE_BREAK) { - nReturn = QCBOR_ERR_BAD_BREAK; - goto Done; - } - - // Record the nesting level for this data item before processing any of - // decrementing and descending. - pDecodedItem->uNestingLevel = DecodeNesting_GetLevel(&(me->nesting)); - - // Process the item just received for descent or decrement, and - // ascent if decrements are enough to close out a definite length array/map - if(IsMapOrArray(pDecodedItem->uDataType)) { - // If the new item is array or map, the nesting level descends - nReturn = DecodeNesting_Descend(&(me->nesting), pDecodedItem); - // Maps and arrays do count in as items in the map/array that encloses - // them so a decrement needs to be done for them too, but that is done - // only when all the items in them have been processed, not when they - // are opened. - } else { - // Decrement the count of items in the enclosing map/array - // If the count in the enclosing map/array goes to zero, that - // triggers a decrement in the map/array above that and - // an ascend in nesting level. - DecodeNesting_DecrementCount(&(me->nesting)); - } - if(nReturn) { - goto Done; - } - - // For indefinite length maps/arrays, looking at any and - // all breaks that might terminate them. The equivalent - // for definite length maps/arrays happens in - // DecodeNesting_DecrementCount(). - if(DecodeNesting_IsNested(&(me->nesting)) && DecodeNesting_IsIndefiniteLength(&(me->nesting))) { - while(UsefulInputBuf_BytesUnconsumed(&(me->InBuf))) { - // Peek forward one item to see if it is a break. - QCBORItem Peek; - size_t uPeek = UsefulInputBuf_Tell(&(me->InBuf)); - nReturn = GetNext_Item(&(me->InBuf), &Peek, NULL); - if(nReturn) { - goto Done; - } - if(Peek.uDataType != QCBOR_TYPE_BREAK) { - // It is not a break, rewind so it can be processed normally. - UsefulInputBuf_Seek(&(me->InBuf), uPeek); - break; - } - // It is a break. Ascend one nesting level. - // The break is consumed. - nReturn = DecodeNesting_BreakAscend(&(me->nesting)); - if(nReturn) { - // break occured outside of an indefinite length array/map - goto Done; - } - } - } - - // Tell the caller what level is next. This tells them what maps/arrays - // were closed out and makes it possible for them to reconstruct - // the tree with just the information returned by GetNext - pDecodedItem->uNextNestLevel = DecodeNesting_GetLevel(&(me->nesting)); - -Done: - return nReturn; -} - - -QCBORError QCBORDecode_GetNext(QCBORDecodeContext *me, QCBORItem *pDecodedItem) -{ - return QCBORDecode_GetNextWithTags(me, pDecodedItem, NULL); -} - - -/* - Decoding items is done in 5 layered functions, one calling the - next one down. If a layer has no work to do for a particular item - it returns quickly. - - - QCBORDecode_GetNext -- The top layer manages the beginnings and - ends of maps and arrays. It tracks descending into and ascending - out of maps/arrays. It processes all breaks that terminate - maps and arrays. - - - GetNext_MapEntry -- This handles the combining of two - items, the label and the data, that make up a map entry. - It only does work on maps. It combines the label and data - items into one labeled item. - - - GetNext_TaggedItem -- This handles the type 6 tagged items. - It accumulates all the tags and combines them with the following - non-tagged item. If the tagged item is something that is understood - like a date, the decoding of that item is invoked. - - - GetNext_FullItem -- This assembles the sub items that make up - an indefinte length string into one string item. It uses the - string allocater to create contiguous space for the item. It - processes all breaks that are part of indefinite length strings. - - - GetNext_Item -- This gets and decodes the most atomic - item in CBOR, the thing with an initial byte containing - the major type. - - Roughly this takes 300 bytes of stack for vars. Need to - evaluate this more carefully and correctly. - - */ - - -/* - Public function, see header qcbor.h file - */ -int QCBORDecode_IsTagged(QCBORDecodeContext *me, const QCBORItem *pItem, uint64_t uTag) -{ - const QCBORTagListIn *pCallerConfiguredTagMap = me->pCallerConfiguredTagList; - - uint8_t uTagBitIndex; - // Do not care about errors in pCallerConfiguredTagMap here. They are - // caught during GetNext() before this is called. - if(TagMapper_Lookup(pCallerConfiguredTagMap, uTag, &uTagBitIndex)) { - return 0; - } - - const uint64_t uTagBit = 0x01ULL << uTagBitIndex; - return (uTagBit & pItem->uTagBits) != 0; -} - - -/* - Public function, see header qcbor.h file - */ -QCBORError QCBORDecode_Finish(QCBORDecodeContext *me) -{ - int nReturn = QCBOR_SUCCESS; - - // Error out if all the maps/arrays are not closed out - if(DecodeNesting_IsNested(&(me->nesting))) { - nReturn = QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN; - goto Done; - } - - // Error out if not all the bytes are consumed - if(UsefulInputBuf_BytesUnconsumed(&(me->InBuf))) { - nReturn = QCBOR_ERR_EXTRA_BYTES; - } - -Done: - // Call the destructor for the string allocator if there is one. - // Always called, even if there are errors; always have to clean up - if(me->pStringAllocator) { - QCBORStringAllocator *pAllocator = (QCBORStringAllocator *)me->pStringAllocator; - if(pAllocator->fDestructor) { - (pAllocator->fDestructor)(pAllocator->pAllocaterContext); - } - } - - return nReturn; -} - - - -/* - -Decoder errors handled in this file - - - Hit end of input before it was expected while decoding type and number QCBOR_ERR_HIT_END - - - negative integer that is too large for C QCBOR_ERR_INT_OVERFLOW - - - Hit end of input while decoding a text or byte string QCBOR_ERR_HIT_END - - - Encountered conflicting tags -- e.g., an item is tagged both a date string and an epoch date QCBOR_ERR_UNSUPPORTED - - - Encontered an array or mapp that has too many items QCBOR_ERR_ARRAY_TOO_LONG - - - Encountered array/map nesting that is too deep QCBOR_ERR_ARRAY_NESTING_TOO_DEEP - - - An epoch date > INT64_MAX or < INT64_MIN was encountered QCBOR_ERR_DATE_OVERFLOW - - - The type of a map label is not a string or int QCBOR_ERR_MAP_LABEL_TYPE - - - Hit end with arrays or maps still open -- QCBOR_ERR_EXTRA_BYTES - - */ - - - - -/* - This is a very primitive memory allocator. It does not track individual - allocations, only a high-water mark. A free or reallotcation must be of - the last chunk allocated. - - All of this following code will get dead-stripped if QCBORDecode_SetMemPool() - is not called. - */ - -typedef struct { - QCBORStringAllocator StringAllocator; - uint8_t *pStart; // First byte that can be allocated - uint8_t *pEnd; // One past the last byte that can be allocated - uint8_t *pFree; // Where the next free chunk is -} MemPool; - - -/* - Internal function for an allocation - - Code Reviewers: THIS FUNCTION DOES POINTER MATH - */ -static UsefulBuf MemPool_Alloc(void *ctx, void *pMem, size_t uNewSize) -{ - MemPool *me = (MemPool *)ctx; - void *pReturn = NULL; - - if(pMem) { - // Realloc case - // This check will work even if uNewSize is a super-large value like UINT64_MAX - if((uNewSize <= (size_t)(me->pEnd - (uint8_t *)pMem)) && ((uint8_t *)pMem >= me->pStart)) { - me->pFree = (uint8_t *)pMem + uNewSize; - pReturn = pMem; - } - } else { - // New chunk case - // This check will work even if uNewSize is a super large value like UINT64_MAX - if(uNewSize <= (size_t)(me->pEnd - me->pFree)) { - pReturn = me->pFree; - me->pFree += uNewSize; - } - } - - return (UsefulBuf){pReturn, uNewSize}; -} - -/* - Internal function to free memory - */ -static void MemPool_Free(void *ctx, void *pOldMem) -{ - MemPool *me = (MemPool *)ctx; - me->pFree = pOldMem; -} - -/* - Public function, see header qcbor.h file - */ -QCBORError QCBORDecode_SetMemPool(QCBORDecodeContext *me, UsefulBuf Pool, bool bAllStrings) -{ - // The idea behind QCBOR_MIN_MEM_POOL_SIZE is - // that the caller knows exactly what size to - // allocate and that the tests can run conclusively - // no matter what size MemPool is - // even though it wastes some memory. MemPool - // will vary depending on pointer size of the - // the machine. QCBOR_MIN_MEM_POOL_SIZE is - // set for pointers up to 64-bits. This - // wastes about 50 bytes on a 32-bit machine. - // This check makes sure things don't go - // horribly wrong. It should optimize out - // when there is no problem as the sizes are - // known at compile time. - if(sizeof(MemPool) > QCBOR_DECODE_MIN_MEM_POOL_SIZE) { - return QCBOR_ERR_MEM_POOL_INTERNAL; - } - - // The first bytes of the Pool passed in are used - // as the context (vtable of sorts) for the memory pool - // allocator. - if(Pool.len < QCBOR_DECODE_MIN_MEM_POOL_SIZE) { - return QCBOR_ERR_BUFFER_TOO_SMALL; - } - MemPool *pMP = (MemPool *)Pool.ptr; - - // Fill in the "vtable" - pMP->StringAllocator.fAllocate = MemPool_Alloc; - pMP->StringAllocator.fFree = MemPool_Free; - pMP->StringAllocator.fDestructor = NULL; - - // Set up the pointers to the memory to be allocated - pMP->pStart = (uint8_t *)Pool.ptr + QCBOR_DECODE_MIN_MEM_POOL_SIZE; - pMP->pFree = pMP->pStart; - pMP->pEnd = (uint8_t *)Pool.ptr + Pool.len; - - // More book keeping of context - pMP->StringAllocator.pAllocaterContext = pMP; - me->pStringAllocator = pMP; - - // The flag indicating when to use the allocator - me->bStringAllocateAll = bAllStrings; - - return QCBOR_SUCCESS; -} - - -/* - Extra little hook to make MemPool testing work right - without adding any code size or overhead to non-test - uses. This will get dead-stripped for non-test use. - - This is not a public function. - */ -size_t MemPoolTestHook_GetPoolSize(void *ctx) -{ - MemPool *me = (MemPool *)ctx; - - return me->pEnd - me->pStart; -} - diff --git a/components/TARGET_PSA/services/attestation/qcbor/src/qcbor_encode.c b/components/TARGET_PSA/services/attestation/qcbor/src/qcbor_encode.c deleted file mode 100644 index d18d811..0000000 --- a/components/TARGET_PSA/services/attestation/qcbor/src/qcbor_encode.c +++ /dev/null @@ -1,651 +0,0 @@ -/*============================================================================== - Copyright (c) 2016-2018, The Linux Foundation. - Copyright (c) 2018-2019, Laurence Lundblade. - All rights reserved. - SPDX-License-Identifier: BSD-3-Clause - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of The Linux Foundation nor the names of its - contributors, nor the name "Laurence Lundblade" may be used to - endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED -WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT -ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS -BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE -OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN -IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ==============================================================================*/ - -/*=================================================================================== - FILE: qcbor_encode.c - - DESCRIPTION: This file contains the implementation of QCBOR. - - EDIT HISTORY FOR FILE: - - This section contains comments describing changes made to the module. - Notice that changes are listed in reverse chronological order. - - when who what, where, why - -------- ---- --------------------------------------------------- - 12/30/18 llundblade Small efficient clever encode of type & argument. - 11/29/18 llundblade Rework to simpler handling of tags and labels. - 11/9/18 llundblade Error codes are now enums. - 11/1/18 llundblade Floating support. - 10/31/18 llundblade Switch to one license that is almost BSD-3. - 09/28/18 llundblade Added bstr wrapping feature for COSE implementation. - 02/05/18 llundbla Works on CPUs which require integer alignment. - Requires new version of UsefulBuf. - 07/05/17 llundbla Add bstr wrapping of maps/arrays for COSE - 03/01/17 llundbla More data types - 11/13/16 llundbla Integrate most TZ changes back into github version. - 09/30/16 gkanike Porting to TZ. - 03/15/16 llundbla Initial Version. - - =====================================================================================*/ - -#include "qcbor.h" -#include "ieee754.h" - - -/*...... This is a ruler that is 80 characters long...........................*/ - - -/* - CBOR's two nesting types, arrays and maps, are tracked here. There is a - limit of QCBOR_MAX_ARRAY_NESTING to the number of arrays and maps - that can be nested in one encoding so the encoding context stays - small enough to fit on the stack. - - When an array / map is opened, pCurrentNesting points to the element - in pArrays that records the type, start position and accumluates a - count of the number of items added. When closed the start position is - used to go back and fill in the type and number of items in the array - / map. - - Encoded output be just items like ints and strings that are - not part of any array / map. That is, the first thing encoded - does not have to be an array or a map. - */ -inline static void Nesting_Init(QCBORTrackNesting *pNesting) -{ - // assumes pNesting has been zeroed - pNesting->pCurrentNesting = &pNesting->pArrays[0]; - // Implied CBOR array at the top nesting level. This is never returned, - // but makes the item count work correctly. - pNesting->pCurrentNesting->uMajorType = CBOR_MAJOR_TYPE_ARRAY; -} - -inline static QCBORError Nesting_Increase(QCBORTrackNesting *pNesting, - uint8_t uMajorType, - uint32_t uPos) -{ - QCBORError nReturn = QCBOR_SUCCESS; - - if(pNesting->pCurrentNesting == &pNesting->pArrays[QCBOR_MAX_ARRAY_NESTING]) { - // trying to open one too many - nReturn = QCBOR_ERR_ARRAY_NESTING_TOO_DEEP; - } else { - pNesting->pCurrentNesting++; - pNesting->pCurrentNesting->uCount = 0; - pNesting->pCurrentNesting->uStart = uPos; - pNesting->pCurrentNesting->uMajorType = uMajorType; - } - return nReturn; -} - -inline static void Nesting_Decrease(QCBORTrackNesting *pNesting) -{ - pNesting->pCurrentNesting--; -} - -inline static QCBORError Nesting_Increment(QCBORTrackNesting *pNesting) -{ - if(1 >= QCBOR_MAX_ITEMS_IN_ARRAY - pNesting->pCurrentNesting->uCount) { - return QCBOR_ERR_ARRAY_TOO_LONG; - } - - pNesting->pCurrentNesting->uCount += 1; - - return QCBOR_SUCCESS; -} - -inline static uint16_t Nesting_GetCount(QCBORTrackNesting *pNesting) -{ - // The nesting count recorded is always the actual number of individiual - // data items in the array or map. For arrays CBOR uses the actual item - // count. For maps, CBOR uses the number of pairs. This function returns - // the number needed for the CBOR encoding, so it divides the number of - // items by two for maps to get the number of pairs. This implementation - // takes advantage of the map major type being one larger the array major - // type, hence uDivisor is either 1 or 2. - const uint16_t uDivisor = pNesting->pCurrentNesting->uMajorType - CBOR_MAJOR_TYPE_ARRAY+1; - - return pNesting->pCurrentNesting->uCount / uDivisor; -} - -inline static uint32_t Nesting_GetStartPos(QCBORTrackNesting *pNesting) -{ - return pNesting->pCurrentNesting->uStart; -} - -inline static uint8_t Nesting_GetMajorType(QCBORTrackNesting *pNesting) -{ - return pNesting->pCurrentNesting->uMajorType; -} - -inline static int Nesting_IsInNest(QCBORTrackNesting *pNesting) -{ - return pNesting->pCurrentNesting == &pNesting->pArrays[0] ? 0 : 1; -} - - - - -/* - Error tracking plan -- Errors are tracked internally and not returned - until Finish is called. The CBOR errors are in me->uError. - UsefulOutBuf also tracks whether the buffer is full or not in its - context. Once either of these errors is set they are never - cleared. Only QCBOREncode_Init() resets them. Or said another way, they must - never be cleared or we'll tell the caller all is good when it is not. - - Only one error code is reported by QCBOREncode_Finish() even if there are - multiple errors. The last one set wins. The caller might have to fix - one error to reveal the next one they have to fix. This is OK. - - The buffer full error tracked by UsefulBuf is only pulled out of - UsefulBuf in Finish() so it is the one that usually wins. UsefulBuf - will never go off the end of the buffer even if it is called again - and again when full. - - It is really tempting to not check for overflow on the count in the - number of items in an array. It would save a lot of code, it is - extremely unlikely that any one will every put 65,000 items in an - array, and the only bad thing that would happen is the CBOR would be - bogus. - - Since this does not parse any input, you could in theory remove all - error checks in this code if you knew the caller called it - correctly. Maybe someday CDDL or some such language will be able to - generate the code to call this and the calling code would always be - correct. This could also automatically size some of the data - structures like array/map nesting resulting in some stack memory - savings. - - Errors returned here fall into two categories: - - Sizes - QCBOR_ERR_BUFFER_TOO_LARGE -- Encoded output exceeded UINT32_MAX - QCBOR_ERR_BUFFER_TOO_SMALL -- output buffer too small - - QCBOR_ERR_ARRAY_NESTING_TOO_DEEP -- Array/map nesting > QCBOR_MAX_ARRAY_NESTING1 - QCBOR_ERR_ARRAY_TOO_LONG -- Too many things added to an array/map - - Nesting constructed incorrectly - QCBOR_ERR_TOO_MANY_CLOSES -- more close calls than opens - QCBOR_ERR_CLOSE_MISMATCH -- Type of close does not match open - QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN -- Finish called without enough closes - */ - - - - -/* - Public function for initialization. See header qcbor.h - */ -void QCBOREncode_Init(QCBOREncodeContext *me, UsefulBuf Storage) -{ - memset(me, 0, sizeof(QCBOREncodeContext)); - UsefulOutBuf_Init(&(me->OutBuf), Storage); - Nesting_Init(&(me->nesting)); -} - - - - -/* - All CBOR data items have a type and an "argument". The argument is - either the value of the item for integer types, the length of the - content for string, byte, array and map types, a tag for major type - 6, and has several uses for major type 7. - - This function encodes the type and the argument. There are several - encodings for the argument depending on how large it is and how it is - used. - - Every encoding of the type and argument has at least one byte, the - "initial byte". - - The top three bits of the initial byte are the major type for the - CBOR data item. The eight major types defined by the standard are - defined as CBOR_MAJOR_TYPE_xxxx in qcbor.h. - - The remaining five bits, known as "additional information", and - possibly more bytes encode the argument. If the argument is less than - 24, then it is encoded entirely in the five bits. This is neat - because it allows you to encode an entire CBOR data item in 1 byte - for many values and types (integers 0-23, true, false, and tags). - - If the argument is larger than 24, then it is encoded in 1,2,4 or 8 - additional bytes, with the number of these bytes indicated by the - values of the 5 bits 24, 25, 25 and 27. - - It is possible to encode a particular argument in many ways with this - representation. This implementation always uses the smallest - possible representation. This conforms with CBOR preferred encoding. - - This function inserts them into the output buffer at the specified - position. AppendEncodedTypeAndNumber() appends to the end. - - This function takes care of converting to network byte order. - - This function is also used to insert floats and doubles. Before this - function is called the float or double must be copied into a - uint64_t. That is how they are passed in. They are then converted to - network byte order correctly. The uMinLen param makes sure that even - - if all the digits of a half, float or double are 0 it is still - correctly encoded in 2, 4 or 8 bytes. - */ - -static void InsertEncodedTypeAndNumber(QCBOREncodeContext *me, - uint8_t uMajorType, - int nMinLen, - uint64_t uNumber, - size_t uPos) -{ - /* - This code does endian conversion without hton or knowing the - endianness of the machine using masks and shifts. This avoids the - dependency on hton and the mess of figuring out how to find the - machine's endianness. - - This is a good efficient implementation on little-endian machines. - A faster and small implementation is possible on big-endian - machines because CBOR/network byte order is big endian. However - big endian machines are uncommon. - - On x86, it is about 200 bytes instead of 500 bytes for the more - formal unoptimized code. - - This also does the CBOR preferred shortest encoding for integers - and is called to do endian conversion for floats. - - It works backwards from the LSB to the MSB as needed. - - Code Reviewers: THIS FUNCTION DOES POINTER MATH - */ - // Holds up to 9 bytes of type and argument - // plus one extra so pointer always points to - // valid bytes. - uint8_t bytes[sizeof(uint64_t)+2]; - // Point to the last bytes and work backwards - uint8_t *pByte = &bytes[sizeof(bytes)-1]; - // This is the 5 bits in the initial byte that is not the major type - uint8_t uAdditionalInfo; - - if(uNumber < CBOR_TWENTY_FOUR && nMinLen == 0) { - // Simple case where argument is < 24 - uAdditionalInfo = uNumber; - } else { - /* - Encode argument in 1,2,4 or 8 bytes. Outer loop - runs once for 1 byte and 4 times for 8 bytes. - Inner loop runs 1, 2 or 4 times depending on - outer loop counter. This works backwards taking - 8 bits off the argument being encoded at a time - until all bits from uNumber have been encoded - and the minimum encoding size is reached. - Minimum encoding size is for floating point - numbers with zero bytes. - */ - static const uint8_t aIterate[] = {1,1,2,4}; - uint8_t i; - for(i = 0; uNumber || nMinLen > 0; i++) { - const uint8_t uIterations = aIterate[i]; - for(int j = 0; j < uIterations; j++) { - *--pByte = uNumber & 0xff; - uNumber = uNumber >> 8; - } - nMinLen -= uIterations; - } - // Additional info is the encoding of the - // number of additional bytes to encode - // argument. - uAdditionalInfo = LEN_IS_ONE_BYTE-1 + i; - } - *--pByte = (uMajorType << 5) + uAdditionalInfo; - - UsefulOutBuf_InsertData(&(me->OutBuf), pByte, &bytes[sizeof(bytes)-1] - pByte, uPos); -} - - -/* - Append the type and number info to the end of the buffer. - - See InsertEncodedTypeAndNumber() function above for details -*/ -inline static void AppendEncodedTypeAndNumber(QCBOREncodeContext *me, - uint8_t uMajorType, - uint64_t uNumber) -{ - // An append is an insert at the end. - InsertEncodedTypeAndNumber(me, - uMajorType, - 0, - uNumber, - UsefulOutBuf_GetEndPosition(&(me->OutBuf))); -} - - - - -/* - Public functions for closing arrays and maps. See header qcbor.h - */ -void QCBOREncode_AddUInt64(QCBOREncodeContext *me, uint64_t uValue) -{ - if(me->uError == QCBOR_SUCCESS) { - AppendEncodedTypeAndNumber(me, CBOR_MAJOR_TYPE_POSITIVE_INT, uValue); - me->uError = Nesting_Increment(&(me->nesting)); - } -} - - -/* - Public functions for closing arrays and maps. See header qcbor.h - */ -void QCBOREncode_AddInt64(QCBOREncodeContext *me, int64_t nNum) -{ - if(me->uError == QCBOR_SUCCESS) { - uint8_t uMajorType; - uint64_t uValue; - - if(nNum < 0) { - // In CBOR -1 encodes as 0x00 with major type negative int. - uValue = (uint64_t)(-nNum - 1); - uMajorType = CBOR_MAJOR_TYPE_NEGATIVE_INT; - } else { - uValue = (uint64_t)nNum; - uMajorType = CBOR_MAJOR_TYPE_POSITIVE_INT; - } - - AppendEncodedTypeAndNumber(me, uMajorType, uValue); - me->uError = Nesting_Increment(&(me->nesting)); - } -} - - -/* - Semi-private function. It is exposed to user of the interface, - but they will usually call one of the inline wrappers rather than this. - - See header qcbor.h - - Does the work of adding some bytes to the CBOR output. Works for a - byte and text strings, which are the same in in CBOR though they have - different major types. This is also used to insert raw - pre-encoded CBOR. - */ -void QCBOREncode_AddBuffer(QCBOREncodeContext *me, uint8_t uMajorType, UsefulBufC Bytes) -{ - if(me->uError == QCBOR_SUCCESS) { - // If it is not Raw CBOR, add the type and the length - if(uMajorType != CBOR_MAJOR_NONE_TYPE_RAW) { - AppendEncodedTypeAndNumber(me, uMajorType, Bytes.len); - } - - // Actually add the bytes - UsefulOutBuf_AppendUsefulBuf(&(me->OutBuf), Bytes); - - // Update the array counting if there is any nesting at all - me->uError = Nesting_Increment(&(me->nesting)); - } -} - - -/* - Public functions for closing arrays and maps. See header qcbor.h - */ -void QCBOREncode_AddTag(QCBOREncodeContext *me, uint64_t uTag) -{ - AppendEncodedTypeAndNumber(me, CBOR_MAJOR_TYPE_OPTIONAL, uTag); -} - - -/* - Semi-private function. It is exposed to user of the interface, - but they will usually call one of the inline wrappers rather than this. - - See header qcbor.h - */ -void QCBOREncode_AddType7(QCBOREncodeContext *me, size_t uSize, uint64_t uNum) -{ - if(me->uError == QCBOR_SUCCESS) { - // This function call takes care of endian swapping for the float / double - InsertEncodedTypeAndNumber(me, - // The major type for floats and doubles - CBOR_MAJOR_TYPE_SIMPLE, - // size makes sure floats with zeros encode correctly - (int)uSize, - // Bytes of the floating point number as a uint - uNum, - // end position because this is append - UsefulOutBuf_GetEndPosition(&(me->OutBuf))); - - me->uError = Nesting_Increment(&(me->nesting)); - } -} - - -/* - Public functions for closing arrays and maps. See header qcbor.h - */ -void QCBOREncode_AddDouble(QCBOREncodeContext *me, double dNum) -{ - const IEEE754_union uNum = IEEE754_DoubleToSmallest(dNum); - - QCBOREncode_AddType7(me, uNum.uSize, uNum.uValue); -} - - -/* - Semi-public function. It is exposed to user of the interface, - but they will usually call one of the inline wrappers rather than this. - - See header qcbor.h -*/ -void QCBOREncode_OpenMapOrArray(QCBOREncodeContext *me, uint8_t uMajorType) -{ - // Add one item to the nesting level we are in for the new map or array - me->uError = Nesting_Increment(&(me->nesting)); - if(me->uError == QCBOR_SUCCESS) { - // The offset where the length of an array or map will get written - // is stored in a uint32_t, not a size_t to keep stack usage smaller. This - // checks to be sure there is no wrap around when recording the offset. - // Note that on 64-bit machines CBOR larger than 4GB can be encoded as long as no - // array / map offsets occur past the 4GB mark, but the public interface - // says that the maximum is 4GB to keep the discussion simpler. - size_t uEndPosition = UsefulOutBuf_GetEndPosition(&(me->OutBuf)); - - // QCBOR_MAX_ARRAY_OFFSET is slightly less than UINT32_MAX so this - // code can run on a 32-bit machine and tests can pass on a 32-bit - // machine. If it was exactly UINT32_MAX, then this code would - // not compile or run on a 32-bit machine and an #ifdef or some - // machine size detection would be needed reducing portability. - if(uEndPosition >= QCBOR_MAX_ARRAY_OFFSET) { - me->uError = QCBOR_ERR_BUFFER_TOO_LARGE; - - } else { - // Increase nesting level because this is a map or array. - // Cast from size_t to uin32_t is safe because of check above - me->uError = Nesting_Increase(&(me->nesting), uMajorType, (uint32_t)uEndPosition); - } - } -} - - -/* - Public functions for closing arrays and maps. See header qcbor.h - */ -void QCBOREncode_CloseMapOrArray(QCBOREncodeContext *me, - uint8_t uMajorType, - UsefulBufC *pWrappedCBOR) -{ - if(me->uError == QCBOR_SUCCESS) { - if(!Nesting_IsInNest(&(me->nesting))) { - me->uError = QCBOR_ERR_TOO_MANY_CLOSES; - } else if(Nesting_GetMajorType(&(me->nesting)) != uMajorType) { - me->uError = QCBOR_ERR_CLOSE_MISMATCH; - } else { - // When the array, map or bstr wrap was started, nothing was done - // except note the position of the start of it. This code goes back - // and inserts the actual CBOR array, map or bstr and its length. - // That means all the data that is in the array, map or wrapped - // needs to be slid to the right. This is done by UsefulOutBuf's - // insert function that is called from inside - // InsertEncodedTypeAndNumber() - const size_t uInsertPosition = Nesting_GetStartPos(&(me->nesting)); - const size_t uEndPosition = UsefulOutBuf_GetEndPosition(&(me->OutBuf)); - // This can't go negative because the UsefulOutBuf always only grows - // and never shrinks. UsefulOutBut itself also has defenses such that - // it won't write were it should not even if given hostile input lengths - const size_t uLenOfEncodedMapOrArray = uEndPosition - uInsertPosition; - - // Length is number of bytes for a bstr and number of items a for map & array - const size_t uLength = uMajorType == CBOR_MAJOR_TYPE_BYTE_STRING ? - uLenOfEncodedMapOrArray : Nesting_GetCount(&(me->nesting)); - - // Actually insert - InsertEncodedTypeAndNumber(me, - uMajorType, // major type bstr, array or map - 0, // no minimum length for encoding - uLength, // either len of bstr or num map / array items - uInsertPosition); // position in out buffer - - // Return pointer and length to the enclosed encoded CBOR. The intended - // use is for it to be hashed (e.g., SHA-256) in a COSE implementation. - // This must be used right away, as the pointer and length go invalid - // on any subsequent calls to this function because of the - // InsertEncodedTypeAndNumber() call that slides data to the right. - if(pWrappedCBOR) { - const UsefulBufC PartialResult = UsefulOutBuf_OutUBuf(&(me->OutBuf)); - const size_t uBstrLen = UsefulOutBuf_GetEndPosition(&(me->OutBuf)) - uEndPosition; - *pWrappedCBOR = UsefulBuf_Tail(PartialResult, uInsertPosition+uBstrLen); - } - Nesting_Decrease(&(me->nesting)); - } - } -} - - - - -/* - Public functions to finish and get the encoded result. See header qcbor.h - */ -QCBORError QCBOREncode_Finish(QCBOREncodeContext *me, UsefulBufC *pEncodedCBOR) -{ - QCBORError uReturn = me->uError; - - if(uReturn != QCBOR_SUCCESS) { - goto Done; - } - - if (Nesting_IsInNest(&(me->nesting))) { - uReturn = QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN; - goto Done; - } - - if(UsefulOutBuf_GetError(&(me->OutBuf))) { - // Stuff didn't fit in the buffer. - // This check catches this condition for all the appends and inserts - // so checks aren't needed when the appends and inserts are performed. - // And of course UsefulBuf will never overrun the input buffer given - // to it. No complex analysis of the error handling in this file is - // needed to know that is true. Just read the UsefulBuf code. - uReturn = QCBOR_ERR_BUFFER_TOO_SMALL; - goto Done; - } - - *pEncodedCBOR = UsefulOutBuf_OutUBuf(&(me->OutBuf)); - -Done: - return uReturn; -} - - -/* - Public functions to finish and get the encoded result. See header qcbor.h - */ -QCBORError QCBOREncode_FinishGetSize(QCBOREncodeContext *me, size_t *puEncodedLen) -{ - UsefulBufC Enc; - - QCBORError nReturn = QCBOREncode_Finish(me, &Enc); - - if(nReturn == QCBOR_SUCCESS) { - *puEncodedLen = Enc.len; - } - - return nReturn; -} - - - - -/* - Notes on the code - - CBOR Major Type Public Function - 0 QCBOREncode_AddUInt64 - 0, 1 QCBOREncode_AddUInt64, QCBOREncode_AddInt64 - 2, 3 QCBOREncode_AddBuffer, Also QCBOREncode_OpenMapOrArray - 4, 5 QCBOREncode_OpenMapOrArray - 6 QCBOREncode_AddTag - 7 QCBOREncode_AddDouble, QCBOREncode_AddType7 - - Object code sizes on X86 with LLVM compiler and -Os (Dec 30, 2018) - - _QCBOREncode_Init 69 - _QCBOREncode_AddUInt64 76 - _QCBOREncode_AddInt64 87 - _QCBOREncode_AddBuffer 113 - _QCBOREncode_AddTag 27 - _QCBOREncode_AddType7 87 - _QCBOREncode_AddDouble 36 - _QCBOREncode_OpenMapOrArray 103 - _QCBOREncode_CloseMapOrArray 181 - _InsertEncodedTypeAndNumber 190 - _QCBOREncode_Finish 72 - _QCBOREncode_FinishGetSize 70 - - Total is about 1.1KB - - _QCBOREncode_CloseMapOrArray is larger because it has a lot - of nesting tracking to do and much of Nesting_ inlines - into it. It probably can't be reduced much. - - If the error returned by Nesting_Increment() can be ignored - because the limit is so high and the consequence of exceeding - is proved to be inconsequential, then a lot of if(me->uError) - instance can be removed, saving some code. - - */ - diff --git a/components/TARGET_PSA/services/attestation/qcbor/test/UsefulBuf_Tests.c b/components/TARGET_PSA/services/attestation/qcbor/test/UsefulBuf_Tests.c deleted file mode 100644 index c0568b4..0000000 --- a/components/TARGET_PSA/services/attestation/qcbor/test/UsefulBuf_Tests.c +++ /dev/null @@ -1,701 +0,0 @@ -/*============================================================================== - Copyright (c) 2016-2018, The Linux Foundation. - Copyright (c) 2018-2019, Laurence Lundblade. - All rights reserved. - SPDX-License-Identifier: BSD-3-Clause - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of The Linux Foundation nor the names of its - contributors, nor the name "Laurence Lundblade" may be used to - endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED -WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT -ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS -BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE -OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN -IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ==============================================================================*/ - -#include "UsefulBuf.h" - - -/* Basic exercise... - - Call all the main public functions. - - Binary compare the result to the expected. - - There is nothing adversarial in this test - */ -const char * UOBTest_NonAdversarial() -{ - const char *szReturn = NULL; - - UsefulBuf_MAKE_STACK_UB(outbuf,50); - - UsefulOutBuf UOB; - - UsefulOutBuf_Init(&UOB, outbuf); - - if(!UsefulOutBuf_AtStart(&UOB)) { - szReturn = "Not at start"; - goto Done; - } - - // Put 7 bytes at beginning of buf - UsefulOutBuf_AppendData(&UOB, "bluster", 7); - - if(UsefulOutBuf_AtStart(&UOB)) { - szReturn = "At start"; - goto Done; - } - - // add a space to end - UsefulOutBuf_AppendByte(&UOB, ' '); - - // Add 5 bytes to the end - UsefulBufC UBC = {"hunny", 5}; - UsefulOutBuf_AppendUsefulBuf(&UOB, UBC); - - // Insert 9 bytes at the beginning, slide the previous stuff right - UsefulOutBuf_InsertData(&UOB, "heffalump", 9, 0); - UsefulOutBuf_InsertByte(&UOB, ' ', 9); - - // Put 9 bytes in at position 10 -- just after "heffalump " - UsefulBufC UBC2 = {"unbounce ", 9}; - UsefulOutBuf_InsertUsefulBuf(&UOB, UBC2, 10); - - // Make it a null terminated string (because all the appends and inserts above not strcpy !) - UsefulOutBuf_AppendByte(&UOB, '\0'); - - - UsefulBufC U = UsefulOutBuf_OutUBuf(&UOB); - - const char *expected = "heffalump unbounce bluster hunny"; - - if(UsefulBuf_IsNULLC(U) || U.len-1 != strlen(expected) || strcmp(expected, U.ptr) || UsefulOutBuf_GetError(&UOB)) { - szReturn = "OutUBuf"; - } - - UsefulBuf_MAKE_STACK_UB(buf, 50); - UsefulBufC Out = UsefulOutBuf_CopyOut(&UOB, buf); - - if(UsefulBuf_IsNULLC(Out) || Out.len-1 != strlen(expected) || strcmp(expected, Out.ptr)) { - szReturn = "CopyOut"; - } - -Done: - return szReturn; -} - - -/* - Append test utility. - pUOB is the buffer to append too - num is the amount to append - expected is the expected return code, 0 or 1 - - returns 0 if test passed - - */ -static int AppendTest(UsefulOutBuf *pUOB, size_t num, int expected) -{ - //reset - UsefulOutBuf_Reset(pUOB); - - // check status first - if(UsefulOutBuf_GetError(pUOB)) - return 1; - - // append the bytes - UsefulOutBuf_AppendData(pUOB, (const uint8_t *)"bluster", num); - - // check error status after - if(UsefulOutBuf_GetError(pUOB) != expected) - return 1; - - return 0; -} - - -/* - Same as append, but takes a position param too - */ -static int InsertTest(UsefulOutBuf *pUOB, size_t num, size_t pos, int expected) -{ - // reset - UsefulOutBuf_Reset(pUOB); - - // check - if(UsefulOutBuf_GetError(pUOB)) - return 1; - - UsefulOutBuf_InsertData(pUOB, (const uint8_t *)"bluster", num, pos); - - if(UsefulOutBuf_GetError(pUOB) != expected) - return 1; - - return 0; -} - - -/* - Boundary conditions to test - - around 0 - - around the buffer size - - around MAX size_t - - - Test these for the buffer size and the cursor, the insert amount, the append amount and the insert position - - */ - -const char *UOBTest_BoundaryConditionsTest() -{ - UsefulBuf_MAKE_STACK_UB(outbuf,2); - - UsefulOutBuf UOB; - - UsefulOutBuf_Init(&UOB, outbuf); - - // append 0 byte to a 2 byte buffer --> success - if(AppendTest(&UOB, 0, 0)) - return "Append 0 bytes failed"; - - // append 1 byte to a 2 byte buffer --> success - if(AppendTest(&UOB, 1, 0)) - return "Append of 1 byte failed"; - - // append 2 byte to a 2 byte buffer --> success - if(AppendTest(&UOB, 2, 0)) - return "Append to fill buffer failed"; - - // append 3 bytes to a 2 byte buffer --> failure - if(AppendTest(&UOB, 3, 1)) - return "Overflow of buffer not caught"; - - // append max size_t to a 2 byte buffer --> failure - if(AppendTest(&UOB, SIZE_MAX, 1)) - return "Append of SIZE_MAX error not caught"; - - if(InsertTest(&UOB, 1, 0, 0)) - return "Insert 1 byte at start failed"; - - if(InsertTest(&UOB, 2, 0, 0)) - return "Insert 2 bytes at start failed"; - - if(InsertTest(&UOB, 3, 0, 1)) - return "Insert overflow not caught"; - - if(InsertTest(&UOB, 1, 1, 1)) - return "Bad insertion point not caught"; - - - UsefulBuf_MAKE_STACK_UB(outBuf2,10); - - UsefulOutBuf_Init(&UOB, outBuf2); - - UsefulOutBuf_Reset(&UOB); - // put data in the buffer - UsefulOutBuf_AppendString(&UOB, "abc123"); - - UsefulOutBuf_InsertString(&UOB, "xyz*&^", 0); - - if(!UsefulOutBuf_GetError(&UOB)) { - return "insert with data should have failed"; - } - - - UsefulOutBuf_Init(&UOB, (UsefulBuf){NULL, SIZE_MAX - 5}); - UsefulOutBuf_AppendData(&UOB, "123456789", SIZE_MAX -6); - if(UsefulOutBuf_GetError(&UOB)) { - return "insert in huge should have succeeded"; - } - - UsefulOutBuf_Init(&UOB, (UsefulBuf){NULL, SIZE_MAX - 5}); - UsefulOutBuf_AppendData(&UOB, "123456789", SIZE_MAX -5); - if(UsefulOutBuf_GetError(&UOB)) { - return "insert in huge should have succeeded"; - } - - UsefulOutBuf_Init(&UOB, (UsefulBuf){NULL, SIZE_MAX - 5}); - UsefulOutBuf_AppendData(&UOB, "123456789", SIZE_MAX - 4); - if(!UsefulOutBuf_GetError(&UOB)) { - return "lengths near max size"; - } - - return NULL; -} - - - - - -// Test function to get size and magic number check - -const char *TestBasicSanity() -{ - UsefulBuf_MAKE_STACK_UB(outbuf,10); - - UsefulOutBuf UOB; - - // First -- make sure that the room left function returns the right amount - UsefulOutBuf_Init(&UOB, outbuf); - - if(UsefulOutBuf_RoomLeft(&UOB) != 10) - return "room left failed"; - - if(!UsefulOutBuf_WillItFit(&UOB, 9)) { - return "it did not fit"; - } - - if(UsefulOutBuf_WillItFit(&UOB, 11)) { - return "it should have not fit"; - } - - - // Next -- make sure that the magic number checking is working right - UOB.magic = 8888; // make magic bogus - - UsefulOutBuf_AppendData(&UOB, (const uint8_t *)"bluster", 7); - - if(!UsefulOutBuf_GetError(&UOB)) - return "magic corruption check failed"; - - - - // Next make sure that the valid data length check is working right - UsefulOutBuf_Init(&UOB, outbuf); - - UOB.data_len = UOB.UB.len+1; // make size bogus - - UsefulOutBuf_AppendData(&UOB, (const uint8_t *)"bluster", 7); - if(!UsefulOutBuf_GetError(&UOB)) - return "valid data check failed"; - - return NULL; -} - - - -const char *UBMacroConversionsTest() -{ - char *szFoo = "foo"; - - UsefulBufC Foo = UsefulBuf_FromSZ(szFoo); - if(Foo.len != 3 || strncmp(Foo.ptr, szFoo, 3)) - return "SZToUsefulBufC failed"; - - UsefulBufC Too = UsefulBuf_FROM_SZ_LITERAL("Toooo"); - if(Too.len != 5 || strncmp(Too.ptr, "Toooo", 5)) - return "UsefulBuf_FROM_SZ_LITERAL failed"; - - uint8_t pB[] = {0x42, 0x6f, 0x6f}; - UsefulBufC Boo = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pB); - if(Boo.len != 3 || strncmp(Boo.ptr, "Boo", 3)) - return "UsefulBuf_FROM_BYTE_ARRAY_LITERAL failed"; - - char *sz = "not const"; // some data for the test - UsefulBuf B = (UsefulBuf){sz, sizeof(sz)}; - UsefulBufC BC = UsefulBuf_Const(B); - if(BC.len != sizeof(sz) || BC.ptr != sz) - return "UsefulBufConst failed"; - - return NULL; -} - - -const char *UBUtilTests() -{ - UsefulBuf UB = NULLUsefulBuf; - - if(!UsefulBuf_IsNULL(UB)){ - return "IsNull failed"; - } - - if(!UsefulBuf_IsEmpty(UB)){ - return "IsEmpty failed"; - } - - if(!UsefulBuf_IsNULLOrEmpty(UB)) { - return "IsNULLOrEmpty failed"; - } - - const UsefulBufC UBC = UsefulBuf_Const(UB); - - if(!UsefulBuf_IsNULLC(UBC)){ - return "IsNull const failed"; - } - - if(!UsefulBuf_IsEmptyC(UBC)){ - return "IsEmptyC failed"; - } - - if(!UsefulBuf_IsNULLOrEmptyC(UBC)){ - return "IsNULLOrEmptyC failed"; - } - - const UsefulBuf UB2 = UsefulBuf_Unconst(UBC); - if(!UsefulBuf_IsEmpty(UB2)) { - return "Back to UB is Empty failed"; - } - - UB.ptr = "x"; // just some valid pointer - - if(UsefulBuf_IsNULL(UB)){ - return "IsNull failed"; - } - - if(!UsefulBuf_IsEmptyC(UBC)){ - return "IsEmpty failed"; - } - - // test the Unconst. - if(UsefulBuf_Unconst(UBC).ptr != NULL) { - return "Unconst failed"; - } - - // Set 100 bytes of '+'; validated a few tests later - UsefulBuf_MAKE_STACK_UB(Temp, 100); - const UsefulBufC TempC = UsefulBuf_Set(Temp, '+'); - - // Try to copy into a buf that is too small and see failure - UsefulBuf_MAKE_STACK_UB(Temp2, 99); - if(!UsefulBuf_IsNULLC(UsefulBuf_Copy(Temp2, TempC))) { - return "Copy should have failed"; - } - - if(UsefulBuf_IsNULLC(UsefulBuf_CopyPtr(Temp2, "xx", 2))) { - return "CopyPtr failed"; - } - - UsefulBufC xxyy = UsefulBuf_CopyOffset(Temp2, 2, UsefulBuf_FROM_SZ_LITERAL("yy")); - if(UsefulBuf_IsNULLC(xxyy)) { - return "CopyOffset Failed"; - } - - if(UsefulBuf_Compare(UsefulBuf_Head(xxyy, 3), UsefulBuf_FROM_SZ_LITERAL("xxy"))) { - return "head failed"; - } - - if(UsefulBuf_Compare(UsefulBuf_Tail(xxyy, 1), UsefulBuf_FROM_SZ_LITERAL("xyy"))) { - return "tail failed"; - } - - if(!UsefulBuf_IsNULLC(UsefulBuf_Head(xxyy, 5))) { - return "head should have failed"; - } - - if(!UsefulBuf_IsNULLC(UsefulBuf_Tail(xxyy, 5))) { - return "tail should have failed"; - } - - if(!UsefulBuf_IsNULLC(UsefulBuf_Tail(NULLUsefulBufC, 0))) { - return "tail of NULLUsefulBufC is not NULLUsefulBufC"; - } - - const UsefulBufC TailResult = UsefulBuf_Tail((UsefulBufC){NULL, 100}, 99); - if(TailResult.ptr != NULL || TailResult.len != 1) { - return "tail of NULL and length incorrect"; - } - - if(!UsefulBuf_IsNULLC(UsefulBuf_CopyOffset(Temp2, 100, UsefulBuf_FROM_SZ_LITERAL("yy")))) { - return "Copy Offset should have failed"; - } - - // Try to copy into a NULL/empty buf and see failure - const UsefulBuf UBNull = NULLUsefulBuf; - if(!UsefulBuf_IsNULLC(UsefulBuf_Copy(UBNull, TempC))) { - return "Copy to NULL should have failed"; - } - - - // Try to set a NULL/empty buf; nothing should happen - UsefulBuf_Set(UBNull, '+'); // This will crash on failure - - // Copy successfully to a buffer - UsefulBuf_MAKE_STACK_UB(Temp3, 101); - if(UsefulBuf_IsNULLC(UsefulBuf_Copy(Temp3, TempC))) { - return "Copy should not have failed"; - } - - static const uint8_t pExpected[] = { - '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', - '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', - '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', - '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', - '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', - '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', - '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', - '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', - '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', - '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', - }; - UsefulBufC Expected = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pExpected); - // This validates comparison for equality and the UsefulBuf_Set - if(UsefulBuf_Compare(Expected, TempC)) { - return "Set / Copy / Compare failed"; - } - - // Compare two empties and expect success - if(UsefulBuf_Compare(NULLUsefulBufC, NULLUsefulBufC)){ - return "Compare Empties failed"; - } - - // Compare with empty and expect the first to be larger - if(UsefulBuf_Compare(Expected, NULLUsefulBufC) <= 0){ - return "Compare with empty failed"; - } - - - static const uint8_t pExpectedBigger[] = { - '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', - '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', - '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', - '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', - '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', - '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', - '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', - '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', - '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', - '+', '+', '+', '+', '+', '+', '+', '+', '+', ',', - }; - const UsefulBufC ExpectedBigger = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pExpectedBigger); - - // Expect -1 when the first arg is smaller - if(UsefulBuf_Compare(Expected, ExpectedBigger) >= 0){ - return "Compare with bigger"; - } - - - static const uint8_t pExpectedSmaller[] = { - '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', - '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', - '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', - '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', - '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', - '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', - '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', - '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', - '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', - '+', '+', '+', '+', '+', '+', '+', '+', '+', '*', - }; - const UsefulBufC ExpectedSmaller = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pExpectedSmaller); - // Expect +1 when the first arg is larger - if(UsefulBuf_Compare(Expected, ExpectedSmaller) <= 0){ - return "Compare with smaller"; - } - - - static const uint8_t pExpectedLonger[] = { - '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', - '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', - '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', - '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', - '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', - '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', - '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', - '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', - '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', - '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', '+' - }; - const UsefulBufC ExpectedLonger = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pExpectedLonger); - - // Expect -1 when the first arg is smaller - if(UsefulBuf_Compare(Expected, ExpectedLonger) >= 0){ - return "Compare with longer"; - } - - - static const uint8_t pExpectedShorter[] = { - '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', - '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', - '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', - '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', - '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', - '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', - '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', - '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', - '+', '+', '+', '+', '+', '+', '+', '+', '+', '+', - '+', '+', '+', '+', '+', '+', '+', '+', '+', - }; - const UsefulBufC ExpectedShorter = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pExpectedShorter); - // Expect +1 with the first arg is larger - if(UsefulBuf_Compare(Expected, ExpectedShorter) <= 0){ - return "Compare with shorter"; - } - - - if(UsefulBuf_IsNULLC(UsefulBuf_Copy(Temp, NULLUsefulBufC))) { - return "Copy null/empty failed"; - } - - // Look for +++++... in +++++... and find it at the beginning - if(0 != UsefulBuf_FindBytes(ExpectedLonger, ExpectedShorter)){ - return "Failed to find"; - } - - // look for ++* in ....++* and find it at the end - static const uint8_t pToFind[] = {'+', '+', '*'}; - const UsefulBufC ToBeFound = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pToFind); - - if(97 != UsefulBuf_FindBytes(ExpectedSmaller, ToBeFound)){ - return "Failed to find 2"; - } - - // look for ++* in ....++, and find it near the end - if(SIZE_MAX != UsefulBuf_FindBytes(ExpectedBigger, ToBeFound)){ - return "Failed to not find"; - } - - // Look for the whole buffer in itself and succeed. - if(0 != UsefulBuf_FindBytes(ExpectedLonger, ExpectedLonger)){ - return "Failed to find 3"; - } - - return NULL; -} - - -const char * UIBTest_IntegerFormat() -{ - UsefulOutBuf_MakeOnStack(UOB,100); - - const uint32_t u32 = 0x0A0B0C0D; // from https://en.wikipedia.org/wiki/Endianness - const uint64_t u64 = 1984738472938472; - const uint16_t u16 = 40000; - const uint8_t u8 = 9; - const float f = (float)314.15; - const double d = 2.1e10; - - - UsefulOutBuf_AppendUint32(&UOB, u32); // Also tests UsefulOutBuf_InsertUint64 and UsefulOutBuf_GetEndPosition - UsefulOutBuf_AppendUint64(&UOB, u64); // Also tests UsefulOutBuf_InsertUint32 - UsefulOutBuf_AppendUint16(&UOB, u16); // Also tests UsefulOutBuf_InsertUint16 - UsefulOutBuf_AppendByte(&UOB, u8); - UsefulOutBuf_AppendFloat(&UOB, f); // Also tests UsefulOutBuf_InsertFloat - UsefulOutBuf_AppendDouble(&UOB, d); // Also tests UsefulOutBuf_InsertDouble - - const UsefulBufC O = UsefulOutBuf_OutUBuf(&UOB); - if(UsefulBuf_IsNULLC(O)) - return "Couldn't output integers"; - - // from https://en.wikipedia.org/wiki/Endianness - const uint8_t pExpectedNetworkOrder[4] = {0x0A, 0x0B, 0x0C, 0x0D}; - if(memcmp(O.ptr, pExpectedNetworkOrder, 4)) { - return "not in network order"; - } - - UsefulInputBuf UIB; - - UsefulInputBuf_Init(&UIB, O); - - if(UsefulInputBuf_Tell(&UIB) != 0) { - return "UsefulInputBuf_Tell failed"; - } - - if(UsefulInputBuf_GetUint32(&UIB) != u32) { - return "u32 out then in failed"; - } - if(UsefulInputBuf_GetUint64(&UIB) != u64) { - return "u64 out then in failed"; - } - if(UsefulInputBuf_GetUint16(&UIB) != u16) { - return "u16 out then in failed"; - } - if(UsefulInputBuf_GetByte(&UIB) != u8) { - return "u8 out then in failed"; - } - if(UsefulInputBuf_GetFloat(&UIB) != f) { - return "float out then in failed"; - } - if(UsefulInputBuf_GetDouble(&UIB) != d) { - return "double out then in failed"; - } - - // Reset and go again for a few more tests - UsefulInputBuf_Init(&UIB, O); - - const UsefulBufC Four = UsefulInputBuf_GetUsefulBuf(&UIB, 4); - if(UsefulBuf_IsNULLC(Four)) { - return "Four is NULL"; - } - if(UsefulBuf_Compare(Four, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pExpectedNetworkOrder))) { - return "Four compare failed"; - } - - if(UsefulInputBuf_BytesUnconsumed(&UIB) != 23){ - return "Wrong number of unconsumed bytes"; - } - - if(!UsefulInputBuf_BytesAvailable(&UIB, 23)){ - return "Wrong number of bytes available I"; - } - - if(UsefulInputBuf_BytesAvailable(&UIB, 24)){ - return "Wrong number of bytes available II"; - } - - UsefulInputBuf_Seek(&UIB, 0); - - if(UsefulInputBuf_GetError(&UIB)) { - return "unexpected error after seek"; - } - - const uint8_t *pGetBytes = (const uint8_t *)UsefulInputBuf_GetBytes(&UIB, 4); - if(pGetBytes == NULL) { - return "GetBytes returns NULL"; - } - - if(memcmp(pGetBytes, pExpectedNetworkOrder, 4)) { - return "Got wrong bytes"; - } - - UsefulInputBuf_Seek(&UIB, 28); - - if(!UsefulInputBuf_GetError(&UIB)) { - return "expected error after seek"; - } - - return NULL; -} - - -const char *UBUTest_CopyUtil() -{ - if(UsefulBufUtil_CopyFloatToUint32(65536.0F) != 0x47800000) { - return "CopyFloatToUint32 failed"; - } - - if(UsefulBufUtil_CopyDoubleToUint64(4e-40L) != 0X37C16C2800000000ULL) { - return "CopyDoubleToUint64 failed"; - } - - if(UsefulBufUtil_CopyUint64ToDouble(0X37C16C2800000000ULL) != 4e-40L) { - return "CopyUint64ToDouble failed"; - } - - if(UsefulBufUtil_CopyUint32ToFloat(0x47800000) != 65536.0F) { - return "CopyUint32ToFloat failed"; - } - - return NULL; -} - - - diff --git a/components/TARGET_PSA/services/attestation/qcbor/test/UsefulBuf_Tests.h b/components/TARGET_PSA/services/attestation/qcbor/test/UsefulBuf_Tests.h deleted file mode 100644 index d85b951..0000000 --- a/components/TARGET_PSA/services/attestation/qcbor/test/UsefulBuf_Tests.h +++ /dev/null @@ -1,51 +0,0 @@ -/*============================================================================== - Copyright (c) 2016-2018, The Linux Foundation. - Copyright (c) 2018, Laurence Lundblade. - All rights reserved. - SPDX-License-Identifier: BSD-3-Clause - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of The Linux Foundation nor the names of its - contributors, nor the name "Laurence Lundblade" may be used to - endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED -WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT -ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS -BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE -OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN -IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ==============================================================================*/ - -#ifndef UsefulBuf_UsefulBuf_Tests_h -#define UsefulBuf_UsefulBuf_Tests_h - -const char * UOBTest_NonAdversarial(void); - -const char * TestBasicSanity(void); - -const char * UOBTest_BoundaryConditionsTest(void); - -const char * UBMacroConversionsTest(void); - -const char * UBUtilTests(void); - -const char * UIBTest_IntegerFormat(void); - -const char * UBUTest_CopyUtil(void); - -#endif diff --git a/components/TARGET_PSA/services/attestation/qcbor/test/float_tests.c b/components/TARGET_PSA/services/attestation/qcbor/test/float_tests.c deleted file mode 100644 index dd211c3..0000000 --- a/components/TARGET_PSA/services/attestation/qcbor/test/float_tests.c +++ /dev/null @@ -1,474 +0,0 @@ -/*============================================================================== - float_tests.c -- tests for float and conversion to/from half-precision - - Copyright (c) 2018-2019, Laurence Lundblade. All rights reserved. - - SPDX-License-Identifier: BSD-3-Clause - - See BSD-3-Clause license in README.md - - Created on 9/19/18 - ==============================================================================*/ - -#include "float_tests.h" -#include "qcbor.h" -#include "half_to_double_from_rfc7049.h" -#include // For INFINITY and NAN and isnan() - - - -static const uint8_t spExpectedHalf[] = { - 0xB1, - 0x64, - 0x7A, 0x65, 0x72, 0x6F, - 0xF9, 0x00, 0x00, // 0.000 - 0x6A, - 0x69, 0x6E, 0x66, 0x69, 0x6E, 0x69, 0x74, 0x69, 0x74, 0x79, - 0xF9, 0x7C, 0x00, // Infinity - 0x73, - 0x6E, 0x65, 0x67, 0x61, 0x74, 0x69, 0x76, 0x65, 0x20, 0x69, 0x6E, 0x66, 0x69, 0x6E, 0x69, 0x74, 0x69, 0x74, 0x79, - 0xF9, 0xFC, 0x00, // -Inifinity - 0x63, - 0x4E, 0x61, 0x4E, - 0xF9, 0x7E, 0x00, // NaN - 0x63, - 0x6F, 0x6E, 0x65, - 0xF9, 0x3C, 0x00, // 1.0 - 0x69, - 0x6F, 0x6E, 0x65, 0x20, 0x74, 0x68, 0x69, 0x72, 0x64, - 0xF9, 0x35, 0x55, // 0.333251953125 - 0x76, - 0x6C, 0x61, 0x72, 0x67, 0x65, 0x73, 0x74, 0x20, 0x68, 0x61, 0x6C, 0x66, 0x2D, 0x70, 0x72, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6F, 0x6E, - 0xF9, 0x7B, 0xFF, // 65504.0 - 0x78, 0x18, 0x74, 0x6F, 0x6F, 0x2D, 0x6C, 0x61, 0x72, 0x67, 0x65, 0x20, 0x68, 0x61, 0x6C, 0x66, 0x2D, 0x70, 0x72, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6F, 0x6E, - 0xF9, 0x7C, 0x00, // Infinity - 0x72, - 0x73, 0x6D, 0x61, 0x6C, 0x6C, 0x65, 0x73, 0x74, 0x20, 0x73, 0x75, 0x62, 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C, - 0xF9, 0x00, 0x01, // 0.000000059604 - 0x6F, - 0x73, 0x6D, 0x61, 0x6C, 0x6C, 0x65, 0x73, 0x74, 0x20, 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C, - 0xF9, 0x03, 0xFF, // 0.0000609755516 - 0x71, - 0x62, 0x69, 0x67, 0x67, 0x65, 0x73, 0x74, 0x20, 0x73, 0x75, 0x62, 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C, - 0xF9, 0x04, 0x00, // 0.000061988 - 0x70, - 0x73, 0x75, 0x62, 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C, 0x20, 0x73, 0x69, 0x6E, 0x67, 0x6C, 0x65, - 0xF9, 0x00, 0x00, - 0x03, - 0xF9, 0xC0, 0x00, // -2 - 0x04, - 0xF9, 0x7E, 0x00, // qNaN - 0x05, - 0xF9, 0x7C, 0x01, // sNaN - 0x06, - 0xF9, 0x7E, 0x0F, // qNaN with payload 0x0f - 0x07, - 0xF9, 0x7C, 0x0F, // sNaN with payload 0x0f - -}; - - -int HalfPrecisionDecodeBasicTests() -{ - UsefulBufC HalfPrecision = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedHalf); - - QCBORDecodeContext DC; - QCBORDecode_Init(&DC, HalfPrecision, 0); - - QCBORItem Item; - - QCBORDecode_GetNext(&DC, &Item); - if(Item.uDataType != QCBOR_TYPE_MAP) { - return -1; - } - - QCBORDecode_GetNext(&DC, &Item); - if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 0.0F) { - return -2; - } - - QCBORDecode_GetNext(&DC, &Item); - if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != INFINITY) { - return -3; - } - - QCBORDecode_GetNext(&DC, &Item); - if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != -INFINITY) { - return -4; - } - - QCBORDecode_GetNext(&DC, &Item); // TODO, is this really converting right? It is carrying payload, but this confuses things. - if(Item.uDataType != QCBOR_TYPE_DOUBLE || !isnan(Item.val.dfnum)) { - return -5; - } - - QCBORDecode_GetNext(&DC, &Item); - if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 1.0F) { - return -6; - } - - QCBORDecode_GetNext(&DC, &Item); - if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 0.333251953125F) { - return -7; - } - - QCBORDecode_GetNext(&DC, &Item); - if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 65504.0F) { - return -8; - } - - QCBORDecode_GetNext(&DC, &Item); - if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != INFINITY) { - return -9; - } - - QCBORDecode_GetNext(&DC, &Item); // TODO: check this - if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 0.0000000596046448F) { - return -10; - } - - QCBORDecode_GetNext(&DC, &Item); // TODO: check this - if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 0.0000609755516F) { - return -11; - } - - QCBORDecode_GetNext(&DC, &Item); // TODO check this - if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 0.0000610351563F) { - return -12; - } - - QCBORDecode_GetNext(&DC, &Item); - if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 0) { - return -13; - } - - QCBORDecode_GetNext(&DC, &Item); - if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != -2.0F) { - return -14; - } - - // TODO: double check these four tests - QCBORDecode_GetNext(&DC, &Item); // qNaN - if(Item.uDataType != QCBOR_TYPE_DOUBLE || UsefulBufUtil_CopyDoubleToUint64(Item.val.dfnum) != 0x7ff8000000000000ULL) { - return -15; - } - QCBORDecode_GetNext(&DC, &Item); // sNaN - if(Item.uDataType != QCBOR_TYPE_DOUBLE || UsefulBufUtil_CopyDoubleToUint64(Item.val.dfnum) != 0x7ff0000000000001ULL) { - return -16; - } - QCBORDecode_GetNext(&DC, &Item); // qNaN with payload 0x0f - if(Item.uDataType != QCBOR_TYPE_DOUBLE || UsefulBufUtil_CopyDoubleToUint64(Item.val.dfnum) != 0x7ff800000000000fULL) { - return -17; - } - QCBORDecode_GetNext(&DC, &Item); // sNaN with payload 0x0f - if(Item.uDataType != QCBOR_TYPE_DOUBLE || UsefulBufUtil_CopyDoubleToUint64(Item.val.dfnum) != 0x7ff000000000000fULL) { - return -18; - } - - if(QCBORDecode_Finish(&DC)) { - return -19; - } - - return 0; -} - - - - -int HalfPrecisionAgainstRFCCodeTest() -{ - for(uint32_t uHalfP = 0; uHalfP < 0xffff; uHalfP += 60) { - unsigned char x[2]; - x[1] = uHalfP & 0xff; - x[0] = uHalfP >> 8; - double d = decode_half(x); - - // Contruct the CBOR for the half-precision float by hand - UsefulBuf_MAKE_STACK_UB(__xx, 3); - UsefulOutBuf UOB; - UsefulOutBuf_Init(&UOB, __xx); - - const uint8_t uHalfPrecInitialByte = HALF_PREC_FLOAT + (CBOR_MAJOR_TYPE_SIMPLE << 5); // 0xf9 - UsefulOutBuf_AppendByte(&UOB, uHalfPrecInitialByte); // The initial byte for a half-precision float - UsefulOutBuf_AppendUint16(&UOB, (uint16_t)uHalfP); - - // Now parse the hand-constructed CBOR. This will invoke the conversion to a float - QCBORDecodeContext DC; - QCBORDecode_Init(&DC, UsefulOutBuf_OutUBuf(&UOB), 0); - - QCBORItem Item; - - QCBORDecode_GetNext(&DC, &Item); - if(Item.uDataType != QCBOR_TYPE_DOUBLE) { - return -1; - } - - //printf("%04x QCBOR:%15.15f RFC: %15.15f (%8x)\n", uHalfP,Item.val.fnum, d , UsefulBufUtil_CopyFloatToUint32(d)); - - if(isnan(d)) { - // The RFC code uses the native instructions which may or may not - // handle sNaN, qNaN and NaN payloads correctly. This test just - // makes sure it is a NaN and doesn't worry about the type of NaN - if(!isnan(Item.val.dfnum)) { - return -3; - } - } else { - if(Item.val.dfnum != d) { - return -2; - } - } - } - return 0; -} - - -/* - {"zero": 0.0, - "negative zero": -0.0, - "infinitity": Infinity, - "negative infinitity": -Infinity, - "NaN": NaN, - "one": 1.0, - "one third": 0.333251953125, - "largest half-precision": 65504.0, - "largest half-precision point one": 65504.1, - "too-large half-precision": 65536.0, - "smallest subnormal": 5.96046448e-8, - "smallest normal": 0.00006103515261202119, - "biggest subnormal": 0.00006103515625, - "subnormal single": 4.00000646641519e-40, - 3: -2.0, - "large single exp": 2.5521177519070385e+38, - "too-large single exp": 5.104235503814077e+38, - "biggest single with prec": 16777216.0, - "first single with prec loss": 16777217.0, - 1: "fin"} - */ -static const uint8_t spExpectedSmallest[] = { - 0xB4, 0x64, 0x7A, 0x65, 0x72, 0x6F, 0xF9, 0x00, 0x00, 0x6D, - 0x6E, 0x65, 0x67, 0x61, 0x74, 0x69, 0x76, 0x65, 0x20, 0x7A, - 0x65, 0x72, 0x6F, 0xF9, 0x80, 0x00, 0x6A, 0x69, 0x6E, 0x66, - 0x69, 0x6E, 0x69, 0x74, 0x69, 0x74, 0x79, 0xF9, 0x7C, 0x00, - 0x73, 0x6E, 0x65, 0x67, 0x61, 0x74, 0x69, 0x76, 0x65, 0x20, - 0x69, 0x6E, 0x66, 0x69, 0x6E, 0x69, 0x74, 0x69, 0x74, 0x79, - 0xF9, 0xFC, 0x00, 0x63, 0x4E, 0x61, 0x4E, 0xF9, 0x7E, 0x00, - 0x63, 0x6F, 0x6E, 0x65, 0xF9, 0x3C, 0x00, 0x69, 0x6F, 0x6E, - 0x65, 0x20, 0x74, 0x68, 0x69, 0x72, 0x64, 0xF9, 0x35, 0x55, - 0x76, 0x6C, 0x61, 0x72, 0x67, 0x65, 0x73, 0x74, 0x20, 0x68, - 0x61, 0x6C, 0x66, 0x2D, 0x70, 0x72, 0x65, 0x63, 0x69, 0x73, - 0x69, 0x6F, 0x6E, 0xF9, 0x7B, 0xFF, 0x78, 0x20, 0x6C, 0x61, - 0x72, 0x67, 0x65, 0x73, 0x74, 0x20, 0x68, 0x61, 0x6C, 0x66, - 0x2D, 0x70, 0x72, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6F, 0x6E, - 0x20, 0x70, 0x6F, 0x69, 0x6E, 0x74, 0x20, 0x6F, 0x6E, 0x65, - 0xFB, 0x40, 0xEF, 0xFC, 0x03, 0x33, 0x33, 0x33, 0x33, 0x78, - 0x18, 0x74, 0x6F, 0x6F, 0x2D, 0x6C, 0x61, 0x72, 0x67, 0x65, - 0x20, 0x68, 0x61, 0x6C, 0x66, 0x2D, 0x70, 0x72, 0x65, 0x63, - 0x69, 0x73, 0x69, 0x6F, 0x6E, 0xFA, 0x47, 0x80, 0x00, 0x00, - 0x72, 0x73, 0x6D, 0x61, 0x6C, 0x6C, 0x65, 0x73, 0x74, 0x20, - 0x73, 0x75, 0x62, 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C, 0xFB, - 0x3E, 0x70, 0x00, 0x00, 0x00, 0x1C, 0x5F, 0x68, 0x6F, 0x73, - 0x6D, 0x61, 0x6C, 0x6C, 0x65, 0x73, 0x74, 0x20, 0x6E, 0x6F, - 0x72, 0x6D, 0x61, 0x6C, 0xFA, 0x38, 0x7F, 0xFF, 0xFF, 0x71, - 0x62, 0x69, 0x67, 0x67, 0x65, 0x73, 0x74, 0x20, 0x73, 0x75, - 0x62, 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C, 0xF9, 0x04, 0x00, - 0x70, 0x73, 0x75, 0x62, 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C, - 0x20, 0x73, 0x69, 0x6E, 0x67, 0x6C, 0x65, 0xFB, 0x37, 0xC1, - 0x6C, 0x28, 0x00, 0x00, 0x00, 0x00, 0x03, 0xF9, 0xC0, 0x00, - 0x70, 0x6C, 0x61, 0x72, 0x67, 0x65, 0x20, 0x73, 0x69, 0x6E, - 0x67, 0x6C, 0x65, 0x20, 0x65, 0x78, 0x70, 0xFA, 0x7F, 0x40, - 0x00, 0x00, 0x74, 0x74, 0x6F, 0x6F, 0x2D, 0x6C, 0x61, 0x72, - 0x67, 0x65, 0x20, 0x73, 0x69, 0x6E, 0x67, 0x6C, 0x65, 0x20, - 0x65, 0x78, 0x70, 0xFB, 0x47, 0xF8, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x78, 0x18, 0x62, 0x69, 0x67, 0x67, 0x65, 0x73, - 0x74, 0x20, 0x73, 0x69, 0x6E, 0x67, 0x6C, 0x65, 0x20, 0x77, - 0x69, 0x74, 0x68, 0x20, 0x70, 0x72, 0x65, 0x63, 0xFA, 0x4B, - 0x80, 0x00, 0x00, 0x78, 0x1B, 0x66, 0x69, 0x72, 0x73, 0x74, - 0x20, 0x73, 0x69, 0x6E, 0x67, 0x6C, 0x65, 0x20, 0x77, 0x69, - 0x74, 0x68, 0x20, 0x70, 0x72, 0x65, 0x63, 0x20, 0x6C, 0x6F, - 0x73, 0x73, 0xFB, 0x41, 0x70, 0x00, 0x00, 0x10, 0x00, 0x00, - 0x00, 0x01, 0x63, 0x66, 0x69, 0x6E -}; - - -int DoubleAsSmallestTest() -{ - UsefulBuf_MAKE_STACK_UB(EncodedHalfsMem, 420); - -#define QCBOREncode_AddDoubleAsSmallestToMap QCBOREncode_AddDoubleToMap -#define QCBOREncode_AddDoubleAsSmallestToMapN QCBOREncode_AddDoubleToMapN - - - QCBOREncodeContext EC; - QCBOREncode_Init(&EC, EncodedHalfsMem); - // These are mostly from https://en.wikipedia.org/wiki/Half-precision_floating-point_format - QCBOREncode_OpenMap(&EC); - // 64 # text(4) - // 7A65726F # "zero" - // F9 0000 # primitive(0) - QCBOREncode_AddDoubleAsSmallestToMap(&EC, "zero", 0.00); - - // 64 # text(4) - // 7A65726F # "negative zero" - // F9 8000 # primitive(0) - QCBOREncode_AddDoubleAsSmallestToMap(&EC, "negative zero", -0.00); - - // 6A # text(10) - // 696E66696E6974697479 # "infinitity" - // F9 7C00 # primitive(31744) - QCBOREncode_AddDoubleAsSmallestToMap(&EC, "infinitity", INFINITY); - - // 73 # text(19) - // 6E6567617469766520696E66696E6974697479 # "negative infinitity" - // F9 FC00 # primitive(64512) - QCBOREncode_AddDoubleAsSmallestToMap(&EC, "negative infinitity", -INFINITY); - - // 63 # text(3) - // 4E614E # "NaN" - // F9 7E00 # primitive(32256) - QCBOREncode_AddDoubleAsSmallestToMap(&EC, "NaN", NAN); - - // TODO: test a few NaN variants - - // 63 # text(3) - // 6F6E65 # "one" - // F9 3C00 # primitive(15360) - QCBOREncode_AddDoubleAsSmallestToMap(&EC, "one", 1.0); - - // 69 # text(9) - // 6F6E65207468697264 # "one third" - // F9 3555 # primitive(13653) - QCBOREncode_AddDoubleAsSmallestToMap(&EC, "one third", 0.333251953125); - - // 76 # text(22) - // 6C6172676573742068616C662D707265636973696F6E # "largest half-precision" - // F9 7BFF # primitive(31743) - QCBOREncode_AddDoubleAsSmallestToMap(&EC, "largest half-precision",65504.0); - - // 76 # text(22) - // 6C6172676573742068616C662D707265636973696F6E # "largest half-precision" - // F9 7BFF # primitive(31743) - QCBOREncode_AddDoubleAsSmallestToMap(&EC, "largest half-precision point one",65504.1); - - // Float 65536.0F is 0x47800000 in hex. It has an exponent of 16, which is larger than 15, the largest half-precision exponent - // 78 18 # text(24) - // 746F6F2D6C617267652068616C662D707265636973696F6E # "too-large half-precision" - // FA 47800000 # primitive(31743) - QCBOREncode_AddDoubleAsSmallestToMap(&EC, "too-large half-precision", 65536.0); - - // The smallest possible half-precision subnormal, but digitis are lost converting - // to half, so this turns into a double - // 72 # text(18) - // 736D616C6C657374207375626E6F726D616C # "smallest subnormal" - // FB 3E700000001C5F68 # primitive(4499096027744984936) - QCBOREncode_AddDoubleAsSmallestToMap(&EC, "smallest subnormal", 0.0000000596046448); - - // The smallest possible half-precision snormal, but digitis are lost converting - // to half, so this turns into a single TODO: confirm this is right - // 6F # text(15) - // 736D616C6C657374206E6F726D616C # "smallest normal" - // FA 387FFFFF # primitive(947912703) - // in hex single is 0x387fffff, exponent -15, significand 7fffff - QCBOREncode_AddDoubleAsSmallestToMap(&EC, "smallest normal", 0.0000610351526F); - - // 71 # text(17) - // 62696767657374207375626E6F726D616C # "biggest subnormal" - // F9 0400 # primitive(1024) - // in hex single is 0x38800000, exponent -14, significand 0 - QCBOREncode_AddDoubleAsSmallestToMap(&EC, "biggest subnormal", 0.0000610351563F); - - // 70 # text(16) - // 7375626E6F726D616C2073696E676C65 # "subnormal single" - // FB 37C16C2800000000 # primitive(4017611261645684736) - QCBOREncode_AddDoubleAsSmallestToMap(&EC, "subnormal single", 4e-40L); - - // 03 # unsigned(3) - // F9 C000 # primitive(49152) - QCBOREncode_AddDoubleAsSmallestToMapN(&EC, 3, -2.0); - - // 70 # text(16) - // 6C617267652073696E676C6520657870 # "large single exp" - // FA 7F400000 # primitive(2134900736) - // (0x01LL << (DOUBLE_NUM_SIGNIFICAND_BITS-1)) | ((127LL + DOUBLE_EXPONENT_BIAS) << DOUBLE_EXPONENT_SHIFT); - QCBOREncode_AddDoubleAsSmallestToMap(&EC, "large single exp", 2.5521177519070385E+38); // Exponent fits single - - // 74 # text(20) - // 746F6F2D6C617267652073696E676C6520657870 # "too-large single exp" - // FB 47F8000000000000 # primitive(5185894970917126144) - // (0x01LL << (DOUBLE_NUM_SIGNIFICAND_BITS-1)) | ((128LL + DOUBLE_EXPONENT_BIAS) << DOUBLE_EXPONENT_SHIFT); - QCBOREncode_AddDoubleAsSmallestToMap(&EC, "too-large single exp", 5.104235503814077E+38); // Exponent too large for single - - // 66 # text(6) - // 646664666465 # "dfdfde" - // FA 4B800000 # primitive(1266679808) - QCBOREncode_AddDoubleAsSmallestToMap(&EC, "biggest single with prec",16777216); // Single with no precision loss - - // 78 18 # text(24) - // 626967676573742073696E676C6520776974682070726563 # "biggest single with prec" - // FA 4B800000 # primitive(1266679808) - QCBOREncode_AddDoubleAsSmallestToMap(&EC, "first single with prec loss",16777217); // Double becuase of precision loss - - // Just a convenient marker when cutting and pasting encoded CBOR - QCBOREncode_AddSZStringToMapN(&EC, 1, "fin"); - - QCBOREncode_CloseMap(&EC); - - UsefulBufC EncodedHalfs; - int nReturn = QCBOREncode_Finish(&EC, &EncodedHalfs); - if(nReturn) { - return -1; - } - - if(UsefulBuf_Compare(EncodedHalfs, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedSmallest))) { - return -3; - } - - return 0; -} - - - -#ifdef NAN_EXPERIMENT -/* - Code for checking what the double to float cast does with - NaNs. Not run as part of tests. Keep it around to - be able to check various platforms and CPUs. - */ - -#define DOUBLE_NUM_SIGNIFICAND_BITS (52) -#define DOUBLE_NUM_EXPONENT_BITS (11) -#define DOUBLE_NUM_SIGN_BITS (1) - -#define DOUBLE_SIGNIFICAND_SHIFT (0) -#define DOUBLE_EXPONENT_SHIFT (DOUBLE_NUM_SIGNIFICAND_BITS) -#define DOUBLE_SIGN_SHIFT (DOUBLE_NUM_SIGNIFICAND_BITS + DOUBLE_NUM_EXPONENT_BITS) - -#define DOUBLE_SIGNIFICAND_MASK (0xfffffffffffffULL) // The lower 52 bits -#define DOUBLE_EXPONENT_MASK (0x7ffULL << DOUBLE_EXPONENT_SHIFT) // 11 bits of exponent -#define DOUBLE_SIGN_MASK (0x01ULL << DOUBLE_SIGN_SHIFT) // 1 bit of sign -#define DOUBLE_QUIET_NAN_BIT (0x01ULL << (DOUBLE_NUM_SIGNIFICAND_BITS-1)) - - -static int NaNExperiments() { - double dqNaN = UsefulBufUtil_CopyUint64ToDouble(DOUBLE_EXPONENT_MASK | DOUBLE_QUIET_NAN_BIT); - double dsNaN = UsefulBufUtil_CopyUint64ToDouble(DOUBLE_EXPONENT_MASK | 0x01); - double dqNaNPayload = UsefulBufUtil_CopyUint64ToDouble(DOUBLE_EXPONENT_MASK | DOUBLE_QUIET_NAN_BIT | 0xf00f); - - float f1 = (float)dqNaN; - float f2 = (float)dsNaN; - float f3 = (float)dqNaNPayload; - - - uint32_t uqNaN = UsefulBufUtil_CopyFloatToUint32((float)dqNaN); - uint32_t usNaN = UsefulBufUtil_CopyFloatToUint32((float)dsNaN); - uint32_t uqNaNPayload = UsefulBufUtil_CopyFloatToUint32((float)dqNaNPayload); - - // Result of this on x86 is that every NaN is a qNaN. The intel - // CVTSD2SS instruction ignores the NaN payload and even converts - // a sNaN to a qNaN. - - return 0; -} -#endif - - - diff --git a/components/TARGET_PSA/services/attestation/qcbor/test/float_tests.h b/components/TARGET_PSA/services/attestation/qcbor/test/float_tests.h deleted file mode 100644 index b7174c8..0000000 --- a/components/TARGET_PSA/services/attestation/qcbor/test/float_tests.h +++ /dev/null @@ -1,23 +0,0 @@ -/*============================================================================== - float_tests.h -- tests for float and conversion to/from half-precision - - Copyright (c) 2018-2019, Laurence Lundblade. All rights reserved. - - SPDX-License-Identifier: BSD-3-Clause - - See BSD-3-Clause license in README.md - - Created on 9/19/18 - ==============================================================================*/ - -#ifndef float_tests_h -#define float_tests_h - -int HalfPrecisionDecodeBasicTests(void); - -int DoubleAsSmallestTest(void); - -int HalfPrecisionAgainstRFCCodeTest(void); - - -#endif /* float_tests_h */ diff --git a/components/TARGET_PSA/services/attestation/qcbor/test/half_to_double_from_rfc7049.c b/components/TARGET_PSA/services/attestation/qcbor/test/half_to_double_from_rfc7049.c deleted file mode 100644 index 4d8fb67..0000000 --- a/components/TARGET_PSA/services/attestation/qcbor/test/half_to_double_from_rfc7049.c +++ /dev/null @@ -1,46 +0,0 @@ -/* - SPDX-License-Identifier: BSD-2-Clause - - Copyright (c) 2013 IETF Trust and the persons identified as the - document authors. All rights reserved. - - This document is subject to BCP 78 and the IETF Trust's Legal - Provisions Relating to IETF Documents - (http://trustee.ietf.org/license-info) in effect on the date of - publication of this document. Please review these documents - carefully, as they describe your rights and restrictions with respect - to this document. Code Components extracted from this document must - include Simplified BSD License text as described in Section 4.e of - the Trust Legal Provisions and are provided without warranty as - described in the Simplified BSD License. - - */ - -/* - This code is from RFC 7049. It is not used in the main implementation - because: - a) it adds a dependency on and ldexp(). - b) the license may be an issue - - QCBOR does support half-precision, but rather than using - floating point math like this, it does it with bit shifting - and masking. - - This code is here to test that code. - - */ - -#include "half_to_double_from_rfc7049.h" - -#include - -double decode_half(unsigned char *halfp) { - int half = (halfp[0] << 8) + halfp[1]; - int exp = (half >> 10) & 0x1f; - int mant = half & 0x3ff; - double val; - if (exp == 0) val = ldexp(mant, -24); - else if (exp != 31) val = ldexp(mant + 1024, exp - 25); - else val = mant == 0 ? INFINITY : NAN; - return half & 0x8000 ? -val : val; -} diff --git a/components/TARGET_PSA/services/attestation/qcbor/test/half_to_double_from_rfc7049.h b/components/TARGET_PSA/services/attestation/qcbor/test/half_to_double_from_rfc7049.h deleted file mode 100644 index 9f69e35..0000000 --- a/components/TARGET_PSA/services/attestation/qcbor/test/half_to_double_from_rfc7049.h +++ /dev/null @@ -1,18 +0,0 @@ -/*============================================================================== - half_to_double_from_rfc7049.h -- interface to IETF float conversion code. - - Copyright (c) 2018-2019, Laurence Lundblade. All rights reserved. - - SPDX-License-Identifier: BSD-3-Clause - - See BSD-3-Clause license in README.md - - Created on 9/23/18 - ==============================================================================*/ - -#ifndef half_to_double_from_rfc7049_h -#define half_to_double_from_rfc7049_h - -double decode_half(unsigned char *halfp); - -#endif /* half_to_double_from_rfc7049_h */ diff --git a/components/TARGET_PSA/services/attestation/qcbor/test/qcbor_decode_tests.c b/components/TARGET_PSA/services/attestation/qcbor/test/qcbor_decode_tests.c deleted file mode 100644 index 9ffc3a0..0000000 --- a/components/TARGET_PSA/services/attestation/qcbor/test/qcbor_decode_tests.c +++ /dev/null @@ -1,2837 +0,0 @@ -/*============================================================================== - Copyright (c) 2016-2018, The Linux Foundation. - Copyright (c) 2018-2019, Laurence Lundblade. - All rights reserved. - SPDX-License-Identifier: BSD-3-Clause - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of The Linux Foundation nor the names of its - contributors, nor the name "Laurence Lundblade" may be used to - endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED -WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT -ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS -BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE -OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN -IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ==============================================================================*/ - -#include "qcbor_decode_tests.h" -#include "qcbor.h" -#include -#include // for fabs() - - -#ifdef PRINT_FUNCTIONS_FOR_DEBUGGING -#include - -static void PrintUsefulBufC(const char *szLabel, UsefulBufC Buf) -{ - if(szLabel) { - printf("%s ", szLabel); - } - - size_t i; - for(i = 0; i < Buf.len; i++) { - uint8_t Z = ((uint8_t *)Buf.ptr)[i]; - printf("%02x ", Z); - } - printf("\n"); - - fflush(stdout); -} - -/*static void printencoded(const char *szLabel, const uint8_t *pEncoded, size_t nLen) -{ - PrintUsefulBufC(szLabel, (UsefulBufC){pEncoded, nLen}); -}*/ -#endif - - -static const uint8_t spExpectedEncodedInts[] = { - 0x98, 0x2f, 0x3b, 0x7f, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x3b, 0x00, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x00, 0x3a, 0xff, 0xff, 0xff, - 0xff, 0x3a, 0xff, 0xff, 0xff, 0xfe, 0x3a, 0xff, - 0xff, 0xff, 0xfd, 0x3a, 0x7f, 0xff, 0xff, 0xff, - 0x3a, 0x7f, 0xff, 0xff, 0xfe, 0x3a, 0x00, 0x01, - 0x00, 0x01, 0x3a, 0x00, 0x01, 0x00, 0x00, 0x39, - 0xff, 0xff, 0x39, 0xff, 0xfe, 0x39, 0xff, 0xfd, - 0x39, 0x01, 0x00, 0x38, 0xff, 0x38, 0xfe, 0x38, - 0xfd, 0x38, 0x18, 0x37, 0x36, 0x20, 0x00, 0x00, - 0x01, 0x16, 0x17, 0x18, 0x18, 0x18, 0x19, 0x18, - 0x1a, 0x18, 0xfe, 0x18, 0xff, 0x19, 0x01, 0x00, - 0x19, 0x01, 0x01, 0x19, 0xff, 0xfe, 0x19, 0xff, - 0xff, 0x1a, 0x00, 0x01, 0x00, 0x00, 0x1a, 0x00, - 0x01, 0x00, 0x01, 0x1a, 0x00, 0x01, 0x00, 0x02, - 0x1a, 0x7f, 0xff, 0xff, 0xff, 0x1a, 0x7f, 0xff, - 0xff, 0xff, 0x1a, 0x80, 0x00, 0x00, 0x00, 0x1a, - 0x80, 0x00, 0x00, 0x01, 0x1a, 0xff, 0xff, 0xff, - 0xfe, 0x1a, 0xff, 0xff, 0xff, 0xff, 0x1b, 0x00, - 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x1b, - 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, - 0x1b, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x1b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff}; - - -// return CBOR error or -1 if type of value doesn't match - -static int IntegerValuesParseTestInternal(QCBORDecodeContext *pDCtx) -{ - QCBORItem Item; - int nCBORError; - - if((nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) - return nCBORError; - if(Item.uDataType != QCBOR_TYPE_ARRAY) - return -1; - - if((nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) - return nCBORError; - if(Item.uDataType != QCBOR_TYPE_INT64 || // Todo; fix this for 32-bit machines - Item.val.int64 != -9223372036854775807LL - 1) - return -1; - - if((nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) - return nCBORError; - if(Item.uDataType != QCBOR_TYPE_INT64 || - Item.val.int64 != -4294967297) - return -1; - - if((nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) - return nCBORError; - if(Item.uDataType != QCBOR_TYPE_INT64 || - Item.val.int64 != -4294967296) - return -1; - - if((nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) - return nCBORError; - if(Item.uDataType != QCBOR_TYPE_INT64 || - Item.val.int64 != -4294967295) - return -1; - - if((nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) - return nCBORError; - if(Item.uDataType != QCBOR_TYPE_INT64 || - Item.val.int64 != -4294967294) - return -1; - - - if((nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) - return nCBORError; - if(Item.uDataType != QCBOR_TYPE_INT64 || - Item.val.int64 != -2147483648) - return -1; - - if((nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) - return nCBORError; - if(Item.uDataType != QCBOR_TYPE_INT64 || - Item.val.int64 != -2147483647) - return -1; - - if((nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) - return nCBORError; - if(Item.uDataType != QCBOR_TYPE_INT64 || - Item.val.int64 != -65538) - return -1; - - if((nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) - return nCBORError; - if(Item.uDataType != QCBOR_TYPE_INT64 || - Item.val.int64 != -65537) - return -1; - - if((nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) - return nCBORError; - if(Item.uDataType != QCBOR_TYPE_INT64 || - Item.val.int64 != -65536) - return -1; - - - if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) - return nCBORError; - if(Item.uDataType != QCBOR_TYPE_INT64 || - Item.val.int64 != -65535) - return -1; - - - if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) - return nCBORError; - if(Item.uDataType != QCBOR_TYPE_INT64 || - Item.val.int64 != -65534) - return -1; - - - if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) - return nCBORError; - if(Item.uDataType != QCBOR_TYPE_INT64 || - Item.val.int64 != -257) - return -1; - - if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) - return nCBORError; - if(Item.uDataType != QCBOR_TYPE_INT64 || - Item.val.int64 != -256) - return -1; - - if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) - return nCBORError; - if(Item.uDataType != QCBOR_TYPE_INT64 || - Item.val.int64 != -255) - return -1; - - if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) - return nCBORError; - if(Item.uDataType != QCBOR_TYPE_INT64 || - Item.val.int64 != -254) - return -1; - - - if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) - return nCBORError; - if(Item.uDataType != QCBOR_TYPE_INT64 || - Item.val.int64 != -25) - return -1; - - - if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) - return nCBORError; - if(Item.uDataType != QCBOR_TYPE_INT64 || - Item.val.int64 != -24) - return -1; - - - if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) - return nCBORError; - if(Item.uDataType != QCBOR_TYPE_INT64 || - Item.val.int64 != -23) - return -1; - - - if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) - return nCBORError; - if(Item.uDataType != QCBOR_TYPE_INT64 || - Item.val.int64 != -1) - return -1; - - - if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) - return nCBORError; - if(Item.uDataType != QCBOR_TYPE_INT64 || - Item.val.int64 != 0) - return -1; - - - if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) - return nCBORError; - if(Item.uDataType != QCBOR_TYPE_INT64 || - Item.val.int64 != 0) - return -1; - - if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) - return nCBORError; - if(Item.uDataType != QCBOR_TYPE_INT64 || - Item.val.int64 != 1) - return -1; - - - if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) - return nCBORError; - if(Item.uDataType != QCBOR_TYPE_INT64 || - Item.val.int64 != 22) - return -1; - - - if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) - return nCBORError; - if(Item.uDataType != QCBOR_TYPE_INT64 || - Item.val.int64 != 23) - return -1; - - - if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) - return nCBORError; - if(Item.uDataType != QCBOR_TYPE_INT64 || - Item.val.int64 != 24) - return -1; - - - if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) - return nCBORError; - if(Item.uDataType != QCBOR_TYPE_INT64 || - Item.val.int64 != 25) - return -1; - - if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) - return nCBORError; - if(Item.uDataType != QCBOR_TYPE_INT64 || - Item.val.int64 != 26) - return -1; - - - if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) - return nCBORError; - if(Item.uDataType != QCBOR_TYPE_INT64 || - Item.val.int64 != 254) - return -1; - - - if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) - return nCBORError; - if(Item.uDataType != QCBOR_TYPE_INT64 || - Item.val.int64 != 255) - return -1; - - - if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) - return nCBORError; - if(Item.uDataType != QCBOR_TYPE_INT64 || - Item.val.int64 != 256) - return -1; - - - if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) - return nCBORError; - if(Item.uDataType != QCBOR_TYPE_INT64 || - Item.val.int64 != 257) - return -1; - - if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) - return nCBORError; - if(Item.uDataType != QCBOR_TYPE_INT64 || - Item.val.int64 != 65534) - return -1; - - - if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) - return nCBORError; - if(Item.uDataType != QCBOR_TYPE_INT64 || - Item.val.int64 != 65535) - return -1; - - - if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) - return nCBORError; - if(Item.uDataType != QCBOR_TYPE_INT64 || - Item.val.int64 != 65536) - return -1; - - if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) - return nCBORError; - if(Item.uDataType != QCBOR_TYPE_INT64 || - Item.val.int64 != 65537) - return -1; - - if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) - return nCBORError; - if(Item.uDataType != QCBOR_TYPE_INT64 || - Item.val.int64 != 65538) - return -1; - - if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) - return nCBORError; - if(Item.uDataType != QCBOR_TYPE_INT64 || - Item.val.int64 != 2147483647) - return -1; - - if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) - return nCBORError; - if(Item.uDataType != QCBOR_TYPE_INT64 || - Item.val.int64 != 2147483647) - return -1; - - if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) - return nCBORError; - if(Item.uDataType != QCBOR_TYPE_INT64 || - Item.val.int64 != 2147483648) - return -1; - - if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) - return nCBORError; - if(Item.uDataType != QCBOR_TYPE_INT64 || - Item.val.int64 != 2147483649) - return -1; - - if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) - return nCBORError; - if(Item.uDataType != QCBOR_TYPE_INT64 || - Item.val.int64 != 4294967294) - return -1; - - - if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) - return nCBORError; - if(Item.uDataType != QCBOR_TYPE_INT64 || - Item.val.int64 != 4294967295) - return -1; - - - if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) - return nCBORError; - if(Item.uDataType != QCBOR_TYPE_INT64 || - Item.val.int64 != 4294967296) - return -1; - - - if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) - return nCBORError; - if(Item.uDataType != QCBOR_TYPE_INT64 || - Item.val.int64 != 4294967297) - return -1; - - - - if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) - return nCBORError; - if(Item.uDataType != QCBOR_TYPE_INT64 || - Item.val.int64 != 9223372036854775807LL) - return -1; - - - if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) - return nCBORError; - if(Item.uDataType != QCBOR_TYPE_UINT64 || - Item.val.uint64 != 18446744073709551615ULL) - return -1; - - - if(QCBORDecode_Finish(pDCtx) != QCBOR_SUCCESS) { - return -1; - } - - return 0; -} - - -/* - Tests the decoding of lots of different integers sizes - and values. - */ - -int IntegerValuesParseTest() -{ - int n; - QCBORDecodeContext DCtx; - - QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedEncodedInts), QCBOR_DECODE_MODE_NORMAL); - - n = IntegerValuesParseTestInternal(&DCtx); - - return(n); -} - - -/* - Creates a simple CBOR array and returns it in *pEncoded. The array is malloced - and needs to be freed. This is used by several tests. - - Two of the inputs can be set. Two other items in the array are fixed. - - */ - -static uint8_t spSimpleArrayBuffer[50]; - -static int CreateSimpleArray(int nInt1, int nInt2, uint8_t **pEncoded, size_t *pEncodedLen) -{ - QCBOREncodeContext ECtx; - int nReturn = -1; - - *pEncoded = NULL; - *pEncodedLen = INT32_MAX; - - // loop runs CBOR encoding twice. First with no buffer to - // calculate the length so buffer can be allocated correctly, - // and last with the buffer to do the actual encoding - do { - QCBOREncode_Init(&ECtx, (UsefulBuf){*pEncoded, *pEncodedLen}); - QCBOREncode_OpenArray(&ECtx); - QCBOREncode_AddInt64(&ECtx, nInt1); - QCBOREncode_AddInt64(&ECtx, nInt2); - QCBOREncode_AddBytes(&ECtx, ((UsefulBufC) {"galactic", 8})); - QCBOREncode_AddBytes(&ECtx, ((UsefulBufC) {"haven token", 11})); - QCBOREncode_CloseArray(&ECtx); - - if(QCBOREncode_FinishGetSize(&ECtx, pEncodedLen)) - goto Done; - - if(*pEncoded != NULL) { - nReturn = 0; - goto Done; - } - - // Use static buffer to avoid dependency on malloc() - if(*pEncodedLen > sizeof(spSimpleArrayBuffer)) { - goto Done; - } - *pEncoded = spSimpleArrayBuffer; - - } while(1); - -Done: - return nReturn; -} - - -/* - {"first integer": 42, - "an array of two strings": [ - "string1", "string2" - ], - "map in a map": { - "bytes 1": h'78787878', - "bytes 2": h'79797979', - "another int": 98, - "text 2": "lies, damn lies and statistics" - } - } - */ - -static uint8_t pValidMapEncoded[] = { - 0xa3, 0x6d, 0x66, 0x69, 0x72, 0x73, 0x74, 0x20, 0x69, 0x6e, - 0x74, 0x65, 0x67, 0x65, 0x72, 0x18, 0x2a, 0x77, 0x61, 0x6e, - 0x20, 0x61, 0x72, 0x72, 0x61, 0x79, 0x20, 0x6f, 0x66, 0x20, - 0x74, 0x77, 0x6f, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, - 0x73, 0x82, 0x67, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x31, - 0x67, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x32, 0x6c, 0x6d, - 0x61, 0x70, 0x20, 0x69, 0x6e, 0x20, 0x61, 0x20, 0x6d, 0x61, - 0x70, 0xa4, 0x67, 0x62, 0x79, 0x74, 0x65, 0x73, 0x20, 0x31, - 0x44, 0x78, 0x78, 0x78, 0x78, 0x67, 0x62, 0x79, 0x74, 0x65, - 0x73, 0x20, 0x32, 0x44, 0x79, 0x79, 0x79, 0x79, 0x6b, 0x61, - 0x6e, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x20, 0x69, 0x6e, 0x74, - 0x18, 0x62, 0x66, 0x74, 0x65, 0x78, 0x74, 0x20, 0x32, 0x78, - 0x1e, 0x6c, 0x69, 0x65, 0x73, 0x2c, 0x20, 0x64, 0x61, 0x6d, - 0x6e, 0x20, 0x6c, 0x69, 0x65, 0x73, 0x20, 0x61, 0x6e, 0x64, - 0x20, 0x73, 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, - 0x73 } ; - -static int ParseOrderedArray(const uint8_t *pEncoded, size_t nLen, int64_t *pInt1, int64_t *pInt2, const uint8_t **pBuf3, size_t *pBuf3Len, const uint8_t **pBuf4, size_t *pBuf4Len) -{ - QCBORDecodeContext DCtx; - QCBORItem Item; - int nReturn = -1; // assume error until success - - QCBORDecode_Init(&DCtx, (UsefulBufC){pEncoded, nLen}, QCBOR_DECODE_MODE_NORMAL); - - // Make sure the first thing is a map - if(QCBORDecode_GetNext(&DCtx, &Item) != 0 || Item.uDataType != QCBOR_TYPE_ARRAY) - goto Done; - - // First integer - if(QCBORDecode_GetNext(&DCtx, &Item) != 0 || Item.uDataType != QCBOR_TYPE_INT64) - goto Done; - *pInt1 = Item.val.int64; - - // Second integer - if(QCBORDecode_GetNext(&DCtx, &Item) != 0 || Item.uDataType != QCBOR_TYPE_INT64) - goto Done; - *pInt2 = Item.val.int64; - - // First string - if(QCBORDecode_GetNext(&DCtx, &Item) != 0 || Item.uDataType != QCBOR_TYPE_BYTE_STRING) - goto Done; - *pBuf3 = Item.val.string.ptr; - *pBuf3Len = Item.val.string.len; - - // Second string - if(QCBORDecode_GetNext(&DCtx, &Item) != 0 || Item.uDataType != QCBOR_TYPE_BYTE_STRING) - goto Done; - *pBuf4 = Item.val.string.ptr; - *pBuf4Len = Item.val.string.len; - - nReturn = 0; - -Done: - return(nReturn); -} - - - - -int SimpleArrayTest() -{ - uint8_t *pEncoded; - size_t nEncodedLen; - - int64_t i1=0, i2=0; - size_t i3=0, i4=0; - const uint8_t *s3= (uint8_t *)""; - const uint8_t *s4= (uint8_t *)""; - - - if(CreateSimpleArray(23, 6000, &pEncoded, &nEncodedLen) < 0) { - return(-1); - } - - ParseOrderedArray(pEncoded, nEncodedLen, &i1, &i2, &s3, &i3, &s4, &i4); - - if(i1 != 23 || - i2 != 6000 || - i3 != 8 || - i4 != 11 || - memcmp("galactic", s3, 8) !=0 || - memcmp("haven token", s4, 11) !=0) { - return(-1); - } - - return(0); -} - - - -static uint8_t spDeepArrays[] = {0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x80}; - -int ParseDeepArrayTest() -{ - QCBORDecodeContext DCtx; - int nReturn = 0; - int i; - - QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spDeepArrays), QCBOR_DECODE_MODE_NORMAL); - - for(i = 0; i < 10; i++) { - QCBORItem Item; - - if(QCBORDecode_GetNext(&DCtx, &Item) != 0 || - Item.uDataType != QCBOR_TYPE_ARRAY || - Item.uNestingLevel != i) { - nReturn = -1; - break; - } - } - - return(nReturn); -} - -// Big enough to test nesting to the depth of 24 -static uint8_t spTooDeepArrays[] = {0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x80}; - -int ParseTooDeepArrayTest() -{ - QCBORDecodeContext DCtx; - int nReturn = 0; - int i; - QCBORItem Item; - - - QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spTooDeepArrays), QCBOR_DECODE_MODE_NORMAL); - - for(i = 0; i < QCBOR_MAX_ARRAY_NESTING1; i++) { - - if(QCBORDecode_GetNext(&DCtx, &Item) != 0 || - Item.uDataType != QCBOR_TYPE_ARRAY || - Item.uNestingLevel != i) { - nReturn = -1; - break; - } - } - - if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_ARRAY_NESTING_TOO_DEEP) - nReturn = -1; - - return(nReturn); -} - - - - -int ShortBufferParseTest() -{ - int nResult = 0; - QCBORDecodeContext DCtx; - int num; - - for(num = sizeof(spExpectedEncodedInts)-1; num; num--) { - int n; - - QCBORDecode_Init(&DCtx, (UsefulBufC){spExpectedEncodedInts, num}, QCBOR_DECODE_MODE_NORMAL); - - n = IntegerValuesParseTestInternal(&DCtx); - - //printf("Len %d, result: %d\n", num, n); - - if(n != QCBOR_ERR_HIT_END) { - nResult = -1; - goto Done; - } - } -Done: - return nResult; -} - - - -int ShortBufferParseTest2() -{ - uint8_t *pEncoded; - int nReturn; - size_t nEncodedLen; - - int64_t i1, i2; - size_t i3, i4; - const uint8_t *s3, *s4; - - nReturn = 0; - - if(CreateSimpleArray(23, 6000, &pEncoded, &nEncodedLen) < 0) { - return(-1); - } - - for(nEncodedLen--; nEncodedLen; nEncodedLen--) { - int nResult = ParseOrderedArray(pEncoded, (uint32_t)nEncodedLen, &i1, &i2, &s3, &i3, &s4, &i4); - if(nResult == 0) { - nReturn = -1; - } - } - - return(nReturn); -} - -/* - Decode and thoroughly check a moderately complex - set of maps - */ -static int ParseMapTest1(QCBORDecodeMode nMode) -{ - QCBORDecodeContext DCtx; - QCBORItem Item; - int nCBORError; - - QCBORDecode_Init(&DCtx, (UsefulBufC){pValidMapEncoded, sizeof(pValidMapEncoded)}, nMode); - - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return nCBORError; - } - if(Item.uDataType != QCBOR_TYPE_MAP || - Item.val.uCount != 3) - return -1; - - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return nCBORError; - } - if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || - Item.uDataType != QCBOR_TYPE_INT64 || - Item.val.int64 != 42 || - Item.uDataAlloc || - Item.uLabelAlloc || - UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("first integer"))) { - return -1; - } - - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return nCBORError; - } - if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || - Item.uDataAlloc || - Item.uLabelAlloc || - UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("an array of two strings")) || - Item.uDataType != QCBOR_TYPE_ARRAY || - Item.val.uCount != 2) - return -1; - - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return nCBORError; - } - if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || - Item.uDataAlloc || - Item.uLabelAlloc || - UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("string1"))) { - return -1; - } - - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return nCBORError; - } - if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || - Item.uDataAlloc || - Item.uLabelAlloc || - UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("string2"))) { - return -1; - } - - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return nCBORError; - } - if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || - Item.uDataAlloc || - Item.uLabelAlloc || - UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("map in a map")) || - Item.uDataType != QCBOR_TYPE_MAP || - Item.val.uCount != 4) { - return -1; - } - - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return nCBORError; - } - if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || - UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("bytes 1"))|| - Item.uDataType != QCBOR_TYPE_BYTE_STRING || - Item.uDataAlloc || - Item.uLabelAlloc || - UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("xxxx"))) { - return -1; - } - - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return nCBORError; - } - if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || - UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("bytes 2")) || - Item.uDataType != QCBOR_TYPE_BYTE_STRING || - Item.uDataAlloc || - Item.uLabelAlloc || - UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("yyyy"))) { - return -1; - } - - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return nCBORError; - } - if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || - Item.uDataAlloc || - Item.uLabelAlloc || - UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("another int")) || - Item.uDataType != QCBOR_TYPE_INT64 || - Item.val.int64 != 98) - return -1; - - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return nCBORError; - } - if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || - UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("text 2"))|| - Item.uDataType != QCBOR_TYPE_TEXT_STRING || - Item.uDataAlloc || - Item.uLabelAlloc || - UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("lies, damn lies and statistics"))) { - return -1; - } - - return 0; -} - - -/* - Decode and thoroughly check a moderately complex - set of maps - */ -int ParseMapAsArrayTest() -{ - QCBORDecodeContext DCtx; - QCBORItem Item; - int nCBORError; - - QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded), QCBOR_DECODE_MODE_MAP_AS_ARRAY); - - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return nCBORError; - } - if(Item.uDataType != QCBOR_TYPE_MAP_AS_ARRAY || - Item.val.uCount != 6) { - return -1; - } - - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return nCBORError; - } - if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || - Item.uDataAlloc || - Item.uLabelAlloc || - Item.uLabelType != QCBOR_TYPE_NONE || - UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("first integer"))) { - return -2; - } - - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return nCBORError; - } - if(Item.uLabelType != QCBOR_TYPE_NONE || - Item.uDataType != QCBOR_TYPE_INT64 || - Item.val.int64 != 42 || - Item.uDataAlloc || - Item.uLabelAlloc) { - return -3; - } - - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return nCBORError; - } - if(Item.uLabelType != QCBOR_TYPE_NONE || - Item.uDataAlloc || - Item.uLabelAlloc || - UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("an array of two strings")) || - Item.uDataType != QCBOR_TYPE_TEXT_STRING) { - return -4; - } - - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return nCBORError; - } - if(Item.uLabelType != QCBOR_TYPE_NONE || - Item.uDataAlloc || - Item.uLabelAlloc || - Item.uDataType != QCBOR_TYPE_ARRAY || - Item.val.uCount != 2) { - return -5; - } - - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return nCBORError; - } - if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || - Item.val.string.len != 7 || - Item.uDataAlloc || - Item.uLabelAlloc || - UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("string1"))) { - return -6; - } - - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return nCBORError; - } - if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || - Item.uDataAlloc || - Item.uLabelAlloc || - UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("string2"))) { - return -7; - } - - - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return nCBORError; - } - if(Item.uLabelType != QCBOR_TYPE_NONE || - Item.uDataAlloc || - Item.uLabelAlloc || - UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("map in a map"))) { - return -8; - } - - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return nCBORError; - } - if(Item.uLabelType != QCBOR_TYPE_NONE || - Item.uDataAlloc || - Item.uLabelAlloc || - Item.uDataType != QCBOR_TYPE_MAP_AS_ARRAY || - Item.val.uCount != 8) { - return -9; - } - - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return nCBORError; - } - if(Item.uLabelType != QCBOR_TYPE_NONE || - UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("bytes 1"))|| - Item.uDataType != QCBOR_TYPE_TEXT_STRING || - Item.uDataAlloc || - Item.uLabelAlloc) { - return -10; - } - - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return nCBORError; - } - if(Item.uLabelType != QCBOR_TYPE_NONE || - Item.uDataType != QCBOR_TYPE_BYTE_STRING || - Item.uDataAlloc || - Item.uLabelAlloc || - UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("xxxx"))) { - return -11; - } - - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return nCBORError; - } - if(Item.uLabelType != QCBOR_TYPE_NONE || - UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("bytes 2")) || - Item.uDataType != QCBOR_TYPE_TEXT_STRING || - Item.uDataAlloc || - Item.uLabelAlloc) { - return -12; - } - - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return nCBORError; - } - if(Item.uLabelType != QCBOR_TYPE_NONE || - Item.uDataType != QCBOR_TYPE_BYTE_STRING || - Item.uDataAlloc || - Item.uLabelAlloc || - UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("yyyy"))) { - return -13; - } - - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return nCBORError; - } - if(Item.uLabelType != QCBOR_TYPE_NONE || - Item.uDataAlloc || - Item.uLabelAlloc || - UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("another int")) || - Item.uDataType != QCBOR_TYPE_TEXT_STRING) { - return -14; - } - - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return nCBORError; - } - if(Item.uLabelType != QCBOR_TYPE_NONE || - Item.uDataAlloc || - Item.uLabelAlloc || - Item.uDataType != QCBOR_TYPE_INT64 || - Item.val.int64 != 98) { - return -15; - } - - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return nCBORError; - } - if(Item.uLabelType != QCBOR_TYPE_NONE || - UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("text 2"))|| - Item.uDataType != QCBOR_TYPE_TEXT_STRING || - Item.uDataAlloc || - Item.uLabelAlloc) { - return -16; - } - - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return nCBORError; - } - if(Item.uLabelType != QCBOR_TYPE_NONE || - Item.uDataType != QCBOR_TYPE_TEXT_STRING || - Item.uDataAlloc || - Item.uLabelAlloc || - UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("lies, damn lies and statistics"))) { - return -17; - } - - return 0; -} - - -/* - Fully or partially decode pValidMapEncoded. When - partially decoding check for the right error code. - How much partial decoding depends on nLevel. - - The partial decodes test error conditions of - incomplete encoded input. - - This could be combined with the above test - and made prettier and maybe a little more - thorough. - */ -static int ExtraBytesTest(int nLevel) -{ - QCBORDecodeContext DCtx; - QCBORItem Item; - int nCBORError; - - QCBORDecode_Init(&DCtx, (UsefulBufC){pValidMapEncoded, sizeof(pValidMapEncoded)}, QCBOR_DECODE_MODE_NORMAL); - - if(nLevel < 1) { - if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_EXTRA_BYTES) { - return -1; - } else { - return 0; - } - } - - - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return nCBORError; - } - if(Item.uDataType != QCBOR_TYPE_MAP || - Item.val.uCount != 3) - return -1; - - if(nLevel < 2) { - if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN) { - return -1; - } else { - return 0; - } - } - - - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return nCBORError; - } - if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || - Item.uDataType != QCBOR_TYPE_INT64 || - Item.val.uCount != 42 || - UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("first integer"))) { - return -1; - } - - if(nLevel < 3) { - if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN) { - return -1; - } else { - return 0; - } - } - - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return nCBORError; - } - if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || - UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("an array of two strings")) || - Item.uDataType != QCBOR_TYPE_ARRAY || - Item.val.uCount != 2) { - return -1; - } - - - if(nLevel < 4) { - if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN) { - return -1; - } else { - return 0; - } - } - - - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return nCBORError; - } - if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || - UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("string1"))) { - return -1; - } - - if(nLevel < 5) { - if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN) { - return -1; - } else { - return 0; - } - } - - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return nCBORError; - } - if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || - UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("string2"))) { - return -1; - } - - if(nLevel < 6) { - if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN) { - return -1; - } else { - return 0; - } - } - - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return nCBORError; - } - if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || - UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("map in a map")) || - Item.uDataType != QCBOR_TYPE_MAP || - Item.val.uCount != 4) - return -1; - - if(nLevel < 7) { - if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN) { - return -1; - } else { - return 0; - } - } - - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return nCBORError; - } - if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || - UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("bytes 1")) || - Item.uDataType != QCBOR_TYPE_BYTE_STRING || - UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("xxxx"))) { - return -1; - } - - if(nLevel < 8) { - if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN) { - return -1; - } else { - return 0; - } - } - - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return nCBORError; - } - if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || - UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("bytes 2")) || - Item.uDataType != QCBOR_TYPE_BYTE_STRING || - UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("yyyy"))) { - return -1; - } - - if(nLevel < 9) { - if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN) { - return -1; - } else { - return 0; - } - } - - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return nCBORError; - } - if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || - UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("another int")) || - Item.uDataType != QCBOR_TYPE_INT64 || - Item.val.int64 != 98) - return -1; - - if(nLevel < 10) { - if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN) { - return -1; - } else { - return 0; - } - } - - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { - return nCBORError; - } - if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || - UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("text 2"))|| - Item.uDataType != QCBOR_TYPE_TEXT_STRING || - UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("lies, damn lies and statistics"))) { - return -1; - } - - if(QCBORDecode_Finish(&DCtx)) { - return -1; - } - - return 0; -} - - - - -int ParseMapTest() -{ - // Parse a moderatly complex map structure very thoroughl - int n = ParseMapTest1(QCBOR_DECODE_MODE_NORMAL); - - n = ParseMapTest1(QCBOR_DECODE_MODE_MAP_STRINGS_ONLY); - - if(!n) { - for(int i = 0; i < 10; i++) { - n = ExtraBytesTest(i); - if(n) { - break; - } - } - } - - return(n); -} - - -static uint8_t spSimpleValues[] = {0x8a, 0xf4, 0xf5, 0xf6, 0xf7, 0xff, 0xe0, 0xf3, 0xf8, 0x00, 0xf8, 0x13, 0xf8, 0x1f, 0xf8, 0x20, 0xf8, 0xff}; - -int ParseSimpleTest() -{ - QCBORDecodeContext DCtx; - QCBORItem Item; - int nCBORError; - - - QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spSimpleValues), QCBOR_DECODE_MODE_NORMAL); - - - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) - return nCBORError; - if(Item.uDataType != QCBOR_TYPE_ARRAY || - Item.val.uCount != 10) - return -1; - - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) - return nCBORError; - if(Item.uDataType != QCBOR_TYPE_FALSE) - return -1; - - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) - return nCBORError; - if(Item.uDataType != QCBOR_TYPE_TRUE) - return -1; - - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) - return nCBORError; - if(Item.uDataType != QCBOR_TYPE_NULL) - return -1; - - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) - return nCBORError; - if(Item.uDataType != QCBOR_TYPE_UNDEF) - return -1; - - // A break - if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_BAD_BREAK) - return -1; - - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) - return nCBORError; - if(Item.uDataType != QCBOR_TYPE_UKNOWN_SIMPLE || Item.val.uSimple != 0) - return -1; - - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) - return nCBORError; - if(Item.uDataType != QCBOR_TYPE_UKNOWN_SIMPLE || Item.val.uSimple != 19) - return -1; - - if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_INVALID_CBOR) - return -1; - - if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_INVALID_CBOR) - return -1; - - if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_INVALID_CBOR) - return -1; - - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) - return nCBORError; - if(Item.uDataType != QCBOR_TYPE_UKNOWN_SIMPLE || Item.val.uSimple != 32) - return -1; - - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) - return nCBORError; - if(Item.uDataType != QCBOR_TYPE_UKNOWN_SIMPLE || Item.val.uSimple != 255) - return -1; - - return 0; - -} - - -struct FailInput { - UsefulBufC Input; - int nError; -}; - - -struct FailInput Failures[] = { - { {(uint8_t[]){0x18}, 1}, QCBOR_ERR_HIT_END }, // 1 byte integer missing the byte - { {(uint8_t[]){0x1c}, 1}, QCBOR_ERR_UNSUPPORTED }, // Reserved additional info = 28 - { {(uint8_t[]){0x1d}, 1}, QCBOR_ERR_UNSUPPORTED }, // Reserved additional info = 29 - { {(uint8_t[]){0x1e}, 1}, QCBOR_ERR_UNSUPPORTED }, // Reserved additional info = 30 - { {(uint8_t[]){0x1f}, 1}, QCBOR_ERR_UNSUPPORTED }, // Indefinite length integer - { {(uint8_t[]){0x3c}, 1}, QCBOR_ERR_UNSUPPORTED }, // 1 byte integer missing the byte - { {(uint8_t[]){0x3d}, 1}, QCBOR_ERR_UNSUPPORTED }, // 1 byte integer missing the byte - { {(uint8_t[]){0x3e}, 1}, QCBOR_ERR_UNSUPPORTED }, // 1 byte integer missing the byte - { {(uint8_t[]){0x3f}, 1}, QCBOR_ERR_UNSUPPORTED }, // Indefinite length negative integer - { {(uint8_t[]){0x41}, 1}, QCBOR_ERR_HIT_END }, // Short byte string - { {(uint8_t[]){0x5c}, 1}, QCBOR_ERR_UNSUPPORTED }, // Reserved additional info = 28 - { {(uint8_t[]){0x5f}, 1}, QCBOR_ERR_UNSUPPORTED }, // Indefinite length byte string - { {(uint8_t[]){0x61}, 1}, QCBOR_ERR_HIT_END }, // Short UTF-8 string - { {(uint8_t[]){0x7c}, 1}, QCBOR_ERR_UNSUPPORTED }, // Reserved additional info = 28 - { {(uint8_t[]){0x7f}, 1}, QCBOR_ERR_UNSUPPORTED }, // Indefinite length UTF-8 string - { {(uint8_t[]){0xff}, 1}, QCBOR_ERR_UNSUPPORTED } , // break - { {(uint8_t[]){0xf8, 0x00}, 2}, QCBOR_ERR_INVALID_CBOR }, // An invalid encoding of a simple type - { {(uint8_t[]){0xf8, 0x1f}, 2}, QCBOR_ERR_INVALID_CBOR }, // An invalid encoding of a simple type - { {(uint8_t[]){0xc0, 0x00}, 2}, QCBOR_ERR_BAD_OPT_TAG }, // Text-based date, with an integer - { {(uint8_t[]){0xc1, 0x41, 0x33}, 3}, QCBOR_ERR_BAD_OPT_TAG }, // Epoch date, with an byte string - { {(uint8_t[]){0xc1, 0xc0, 0x00}, 3}, QCBOR_ERR_BAD_OPT_TAG }, // tagged as both epoch and string dates - { {(uint8_t[]){0xc2, 0x00}, 2}, QCBOR_ERR_BAD_OPT_TAG } // big num tagged an int, not a byte string - -}; - - -int FailureTests() -{ - int nResult = 0; - - struct FailInput *pFEnd = &Failures[0] + sizeof(Failures)/sizeof(struct FailInput); - - for(struct FailInput *pF = &Failures[0]; pF < pFEnd ;pF++) { - QCBORDecodeContext DCtx; - QCBORItem Item; - int nCBORError; - - QCBORDecode_Init(&DCtx, pF->Input, QCBOR_DECODE_MODE_NORMAL); - - while(1) { - nCBORError = QCBORDecode_GetNext(&DCtx, &Item); - if(QCBOR_ERR_HIT_END == nCBORError) { - break; - } - if(nCBORError != pF->nError) { - nResult = 1; - break; - } - } - } - - { - QCBORDecodeContext DCtx; - QCBORItem Item; - int nCBORError; - - QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spSimpleValues), QCBOR_DECODE_MODE_NORMAL); - - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) - return nCBORError; - if(Item.uDataType != QCBOR_TYPE_ARRAY || - Item.val.uCount != 10) - return -1; - - DCtx.InBuf.magic = 0; // Corrupt the UsefulInputBuf - - nCBORError = QCBORDecode_GetNext(&DCtx, &Item); - if(nCBORError != QCBOR_ERR_HIT_END) - return -1; - } - - - return nResult; -} - - -/* Try all 256 values of the byte at nLen including recursing for - each of the values to try values at nLen+1 ... up to nLenMax - */ -static void ComprehensiveInputRecurser(uint8_t *pBuf, int nLen, int nLenMax) -{ - if(nLen >= nLenMax) { - return; - } - - for(int inputByte = 0; inputByte < 256; inputByte++) { - // Set up the input - pBuf[nLen] = inputByte; - const UsefulBufC Input = {pBuf, nLen+1}; - - // Get ready to parse - QCBORDecodeContext DCtx; - QCBORDecode_Init(&DCtx, Input, QCBOR_DECODE_MODE_NORMAL); - - // Parse by getting the next item until an error occurs - // Just about every possible decoder error can occur here - // The goal of this test is not to check for the correct - // error since that is not really possible. It is to - // see that there is no crash on hostile input. - while(1) { - QCBORItem Item; - QCBORError nCBORError = QCBORDecode_GetNext(&DCtx, &Item); - if(nCBORError != QCBOR_SUCCESS) { - break; - } - } - - ComprehensiveInputRecurser(pBuf, nLen+1, nLenMax); - } -} - - -/* - Public function for initialization. See header qcbor.h - */ -int ComprehensiveInputTest() -{ - // Size 2 tests 64K inputs and runs quickly - uint8_t pBuf[2]; - - ComprehensiveInputRecurser(pBuf, 0, sizeof(pBuf)); - - return 0; -} - - -/* - Public function for initialization. See header qcbor.h - */ -int BigComprehensiveInputTest() -{ - // size 3 tests 16 million inputs and runs OK - // in seconds on fast machines. Size 4 takes - // 10+ minutes and 5 half a day on fast - // machines. This test is kept separate from - // the others so as to no slow down the use - // of them as a very frequent regression. - uint8_t pBuf[3]; // - - ComprehensiveInputRecurser(pBuf, 0, sizeof(pBuf)); - - return 0; -} - - -static uint8_t spDateTestInput[] = { - 0xc0, // tag for string date - 0x6a, '1','9','8','5','-','0','4','-','1','2', // Date string - - 0xc1, // tag for epoch date - 0x1a, 0x53, 0x72, 0x4E, 0x00, // Epoch date 1400000000; Tue, 13 May 2014 16:53:20 GMT - - // CBOR_TAG_B64 - 0xc1, 0xcf, 0xd8, 0x22, // 0xee, // Epoch date with extra tags TODO: fix this test - 0x1a, 0x53, 0x72, 0x4E, 0x01, - - 0xc1, // tag for epoch date - 0x1b, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // Too large integer - - 0xc1, // tag for epoch date - 0xfa, 0x3f, 0x8c, 0xcc, 0xcd, // double with value 1.1 - - 0xc1, // tag for epoch date - 0xfa, 0x7f, 0x7f, 0xff, 0xff // 3.4028234663852886e+38 too large - -}; - - -// have to check float expected only to within an epsilon -int CHECK_EXPECTED_DOUBLE(double val, double expected) { - - double diff = val - expected; - - diff = fabs(diff); - - return diff > 0.0000001; -} - - -int DateParseTest() -{ - QCBORDecodeContext DCtx; - QCBORItem Item; - int nCBORError; - - QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spDateTestInput), QCBOR_DECODE_MODE_NORMAL); - - const uint64_t uTags[] = {15}; - QCBORTagListIn TagList = {1, uTags}; - - QCBORDecode_SetCallerConfiguredTagList(&DCtx, &TagList); - - // String date - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) - return -1; - if(Item.uDataType != QCBOR_TYPE_DATE_STRING || - UsefulBuf_Compare(Item.val.dateString, UsefulBuf_FromSZ("1985-04-12"))){ - return -2; - } - - // Epoch date - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) - return -3; - if(Item.uDataType != QCBOR_TYPE_DATE_EPOCH || - Item.val.epochDate.nSeconds != 1400000000 || - Item.val.epochDate.fSecondsFraction != 0 ) { - return -4; - } - - // Epoch date with extra CBOR_TAG_B64 tag that doesn't really mean anything - // but want to be sure extra tag doesn't cause a problem - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) - return -5; - if(Item.uDataType != QCBOR_TYPE_DATE_EPOCH || - Item.val.epochDate.nSeconds != 1400000001 || - Item.val.epochDate.fSecondsFraction != 0 || - !QCBORDecode_IsTagged(&DCtx, &Item, CBOR_TAG_B64)) { - return -6; - } - - // Epoch date that is too large for our representation - if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_DATE_OVERFLOW) { - return -7; - } - - // Epoch date in float format with fractional seconds - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) - return -8; - if(Item.uDataType != QCBOR_TYPE_DATE_EPOCH || - Item.val.epochDate.nSeconds != 1 || - CHECK_EXPECTED_DOUBLE(Item.val.epochDate.fSecondsFraction, 0.1 )) { - return -9; - } - - // Epoch date float that is too large for our representation - if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_DATE_OVERFLOW) { - return -10; - } - - // TODO: could use a few more tests with float, double, and half precsion and negative (but coverage is still pretty good) - - return 0; -} - -// Really simple basic input for tagging test -static uint8_t spOptTestInput[] = { - 0xd9, 0xd9, 0xf7, // CBOR magic number - 0x81, // Array of one - 0xd8, 0x04, // non-preferred serialization of tag 4 - 0x82, 0x01, 0x03}; // fraction 1/3 - -static uint8_t spEncodedLargeTag[] = {0xdb, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x80}; - -// 0x9192939495969798, 0x88, 0x01, 0x04 -static uint8_t spLotsOfTags[] = {0xdb, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0xd8, 0x88, 0xc5, 0xc4, 0x80}; - -/* - The cbor.me parse of this. - 55799(55799(55799({6(7(-23)): 5859837686836516696(7({7(-20): 11({17(-18): 17(17(17("Organization"))), - 9(-17): 773("SSG"), -15: 4(5(6(7(8(9(10(11(12(13(14(15("Confusion")))))))))))), 17(-16): 17("San Diego"), - 17(-14): 17("US")}), 23(-19): 19({-11: 9({-9: -7}), - 90599561(90599561(90599561(-10))): 12(h'0102030405060708090A')})})), - 16(-22): 23({11(8(7(-5))): 8(-3)})}))) - */ -static uint8_t spCSRWithTags[] = { - 0xd9, 0xd9, 0xf7, 0xd9, 0xd9, 0xf7, 0xd9, 0xd9, 0xf7, 0xa2, - 0xc6, 0xc7, 0x36, - 0xdb, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0xc7, 0xa2, - 0xda, 0x00, 0x00, 0x00, 0x07, 0x33, - 0xcb, 0xa5, - 0xd1, 0x31, - 0xd1, 0xd1, 0xd1, 0x6c, - 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0xc9, 0x30, - 0xd9, 0x03, 0x05, 0x63, - 0x53, 0x53, 0x47, - 0x2e, - 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0x69, - 0x43, 0x6f, 0x6e, 0x66, 0x75, 0x73, 0x69, 0x6f, 0x6e, - 0xd1, 0x2f, - 0xd1, 0x69, - 0x53, 0x61, 0x6e, 0x20, 0x44, 0x69, 0x65, 0x67, 0x6f, - 0xd1, 0x2d, - 0xd1, 0x62, - 0x55, 0x53, - 0xd7, 0x32, - 0xd3, 0xa2, - 0x2a, - 0xc9, 0xa1, - 0x28, - 0x26, - 0xda, 0x05, 0x66, 0x70, 0x89, 0xda, 0x05, 0x66, 0x70, 0x89, 0xda, 0x05, 0x66, 0x70, 0x89, 0x29, - 0xcc, 0x4a, - 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,0x07, 0x08, 0x09, 0x0a, - 0xd0, 0x35, - 0xd7, 0xa1, - 0xcb, 0xc8, 0xc7, 0x24, - 0xc8, 0x22}; - -static int CheckCSRMaps(QCBORDecodeContext *pDC); - - -int OptTagParseTest() -{ - QCBORDecodeContext DCtx; - QCBORItem Item; - - QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spOptTestInput), QCBOR_DECODE_MODE_NORMAL); - - //------------------------- - // This text matches the magic number tag and the fraction tag - if(QCBORDecode_GetNext(&DCtx, &Item)) { - return -2; - } - if(Item.uDataType != QCBOR_TYPE_ARRAY || - !QCBORDecode_IsTagged(&DCtx, &Item, CBOR_TAG_CBOR_MAGIC)) { - return -3; - } - - if(QCBORDecode_GetNext(&DCtx, &Item)) { - return -4; - } - if(Item.uDataType != QCBOR_TYPE_ARRAY || - !QCBORDecode_IsTagged(&DCtx, &Item, CBOR_TAG_FRACTION) || - Item.val.uCount != 2) { - return -5; - } - - // -------------------------------- - // This test decodes the very large tag, but it is not in - // any list so it is ignored. - QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spEncodedLargeTag), QCBOR_DECODE_MODE_NORMAL); - if(QCBORDecode_GetNext(&DCtx, &Item)) { - return -6; - } - if(Item.uTagBits) { - return -7; - } - - // ---------------------------------- - // This test sets up a caller-config list that includes the very large tage and then matches it. - QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spEncodedLargeTag), QCBOR_DECODE_MODE_NORMAL); - const uint64_t puList[] = {0x9192939495969798, 257}; - const QCBORTagListIn TL = {2, puList}; - QCBORDecode_SetCallerConfiguredTagList(&DCtx, &TL); - - if(QCBORDecode_GetNext(&DCtx, &Item)) { - return -8; - } - if(Item.uDataType != QCBOR_TYPE_ARRAY || - !QCBORDecode_IsTagged(&DCtx, &Item, 0x9192939495969798) || - QCBORDecode_IsTagged(&DCtx, &Item, 257) || - QCBORDecode_IsTagged(&DCtx, &Item, CBOR_TAG_BIGFLOAT) || - Item.val.uCount != 0) { - return -9; - } - - //------------------------ - // This test sets up a caller-configured list, and looks up something not in it - const uint64_t puLongList[17] = {1,2,1}; - const QCBORTagListIn TLLong = {17, puLongList}; - QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spEncodedLargeTag), QCBOR_DECODE_MODE_NORMAL); - QCBORDecode_SetCallerConfiguredTagList(&DCtx, &TLLong); - if(QCBORDecode_GetNext(&DCtx, &Item)) { - return -11; - } - - // ----------------------- - // This tests retrievel of the full tag list - QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spLotsOfTags), QCBOR_DECODE_MODE_NORMAL); - uint64_t puTags[16]; - QCBORTagListOut Out = {0, 4, puTags}; - if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { - return -12; - } - if(puTags[0] != 0x9192939495969798 || - puTags[1] != 0x88 || - puTags[2] != 0x05 || - puTags[3] != 0x04) { - return -13; - } - - // ---------------------- - // This text if too small of an out list - QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spLotsOfTags), QCBOR_DECODE_MODE_NORMAL); - QCBORTagListOut OutSmall = {0, 3, puTags}; - if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &OutSmall) != QCBOR_ERR_TOO_MANY_TAGS) { - return -14; - } - - // --------------- - // Parse a version of the "CSR" that has had a ton of tags randomly inserted - QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spCSRWithTags), QCBOR_DECODE_MODE_NORMAL); - int n = CheckCSRMaps(&DCtx); - if(n) { - return n-2000; - } - - Out = (QCBORTagListOut){0,16, puTags}; - QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spCSRWithTags), QCBOR_DECODE_MODE_NORMAL); - - const uint64_t puTagList[] = {773, 1, 90599561}; - const QCBORTagListIn TagList = {3, puTagList}; - QCBORDecode_SetCallerConfiguredTagList(&DCtx, &TagList); - - - if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { - return -100; - } - if(Item.uDataType != QCBOR_TYPE_MAP || - !QCBORDecode_IsTagged(&DCtx, &Item, CBOR_TAG_CBOR_MAGIC) || - QCBORDecode_IsTagged(&DCtx, &Item, 90599561) || - QCBORDecode_IsTagged(&DCtx, &Item, CBOR_TAG_DATE_EPOCH) || - Item.val.uCount != 2 || - puTags[0] != CBOR_TAG_CBOR_MAGIC || - puTags[1] != CBOR_TAG_CBOR_MAGIC || - puTags[2] != CBOR_TAG_CBOR_MAGIC || - Out.uNumUsed != 3) { - return -101; - } - - if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { - return -102; - } - if(Item.uDataType != QCBOR_TYPE_MAP || - QCBORDecode_IsTagged(&DCtx, &Item, CBOR_TAG_CBOR_MAGIC) || - QCBORDecode_IsTagged(&DCtx, &Item, 6) || - QCBORDecode_IsTagged(&DCtx, &Item, 7) || // item is tagged 7, but 7 is not configured to be recognized - Item.val.uCount != 2 || - puTags[0] != 5859837686836516696 || - puTags[1] != 7 || - Out.uNumUsed != 2) { - return -103; - } - - if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { - return -104; - } - if(Item.uDataType != QCBOR_TYPE_MAP || - Item.uTagBits || - Item.val.uCount != 5 || - puTags[0] != 0x0b || - Out.uNumUsed != 1) { - return -105; - } - - if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { - return -106; - } - if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || - !QCBORDecode_IsTagged(&DCtx, &Item, CBOR_TAG_COSE_MAC0) || - Item.val.string.len != 12 || - puTags[0] != CBOR_TAG_COSE_MAC0 || - puTags[1] != CBOR_TAG_COSE_MAC0 || - puTags[2] != CBOR_TAG_COSE_MAC0 || - Out.uNumUsed != 3) { - return -105; - } - - if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { - return -107; - } - if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || - !QCBORDecode_IsTagged(&DCtx, &Item, 773) || - Item.val.string.len != 3 || - puTags[0] != 773 || - Out.uNumUsed != 1) { - return -108; - } - - if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { - return -109; - } - if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || - !QCBORDecode_IsTagged(&DCtx, &Item, 4) || - Item.val.string.len != 9 || - puTags[0] != 4 || - puTags[11] != 0x0f || - Out.uNumUsed != 12) { - return -110; - } - - if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { - return -111; - } - if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || - !QCBORDecode_IsTagged(&DCtx, &Item, 17) || - Item.val.string.len != 9 || - puTags[0] != 17 || - Out.uNumUsed != 1) { - return -112; - } - - if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { - return -111; - } - if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || - !QCBORDecode_IsTagged(&DCtx, &Item, 17) || - Item.val.string.len != 2 || - puTags[0] != 17 || - Out.uNumUsed != 1) { - return -112; - } - - if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { - return -113; - } - if(Item.uDataType != QCBOR_TYPE_MAP || - QCBORDecode_IsTagged(&DCtx, &Item, 19) || - Item.val.uCount != 2 || - puTags[0] != 19 || - Out.uNumUsed != 1) { - return -114; - } - - if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { - return -115; - } - if(Item.uDataType != QCBOR_TYPE_MAP || - QCBORDecode_IsTagged(&DCtx, &Item, 9) || - Item.uTagBits || - Item.val.uCount != 1 || - puTags[0] != 9 || - Out.uNumUsed != 1) { - return -116; - } - - if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { - return -116; - } - if(Item.uDataType != QCBOR_TYPE_INT64 || - Item.val.int64 != -7 || - Item.uTagBits || - Out.uNumUsed != 0) { - return -117; - } - - if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { - return -118; - } - if(Item.uDataType != QCBOR_TYPE_BYTE_STRING || - Item.val.string.len != 10 || - Item.uTagBits || - puTags[0] != 12 || - Out.uNumUsed != 1) { - return -119; - } - - if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { - return -120; - } - if(Item.uDataType != QCBOR_TYPE_MAP || - !QCBORDecode_IsTagged(&DCtx, &Item, CBOR_TAG_ENC_AS_B16) || - Item.val.uCount != 1 || - puTags[0] != 0x17 || - Out.uNumUsed != 1) { - return -121; - } - - if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { - return -122; - } - if(Item.uDataType != QCBOR_TYPE_INT64 || - QCBORDecode_IsTagged(&DCtx, &Item, 8) || - Item.val.int64 != -3 || - puTags[0] != 8 || - Out.uNumUsed != 1) { - return -123; - } - - if(QCBORDecode_Finish(&DCtx)) { - return -124; - } - - return 0; -} - - - - -static uint8_t spBigNumInput[] = { - 0x83, - 0xC2, 0x49, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xC3, 0x49, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xA4, - 0x63, 0x42, 0x4E, 0x2B, - 0xC2, 0x49, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x18, 0x40, - 0xC2, 0x49, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x63, 0x42, 0x4E, 0x2D, - 0xC3, 0x49, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x38, 0x3F, - 0xC3, 0x49, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - - -static uint8_t spBigNum[] = {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - - -int BignumParseTest() -{ - QCBORDecodeContext DCtx; - QCBORItem Item; - int nCBORError; - - QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBigNumInput), QCBOR_DECODE_MODE_NORMAL); - - - // - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) - return -1; - if(Item.uDataType != QCBOR_TYPE_ARRAY) { - return -1; - } - - // - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) - return -1; - if(Item.uDataType != QCBOR_TYPE_POSBIGNUM || - UsefulBuf_Compare(Item.val.bigNum, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBigNum))){ - return -1; - } - - // - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) - return -1; - if(Item.uDataType != QCBOR_TYPE_NEGBIGNUM || - UsefulBuf_Compare(Item.val.bigNum, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBigNum))){ - return -1; - } - - // - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) - return -1; - if(Item.uDataType != QCBOR_TYPE_MAP) { - return -1; - } - - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) - return -1; - if(Item.uDataType != QCBOR_TYPE_POSBIGNUM || - Item.uLabelType != QCBOR_TYPE_TEXT_STRING || - UsefulBuf_Compare(Item.val.bigNum, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBigNum))){ - return -1; - } - - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) - return -1; - if(Item.uDataType != QCBOR_TYPE_POSBIGNUM || - Item.uLabelType != QCBOR_TYPE_INT64 || - Item.label.int64 != 64 || - UsefulBuf_Compare(Item.val.bigNum, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBigNum))){ - return -1; - } - - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) - return -1; - if(Item.uDataType != QCBOR_TYPE_NEGBIGNUM || - Item.uLabelType != QCBOR_TYPE_TEXT_STRING || - UsefulBuf_Compare(Item.val.bigNum, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBigNum))){ - return -1; - } - - if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) - return -1; - if(Item.uDataType != QCBOR_TYPE_NEGBIGNUM || - Item.uLabelType != QCBOR_TYPE_INT64 || - Item.label.int64 != -64 || - UsefulBuf_Compare(Item.val.bigNum, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBigNum))){ - return -1; - } - - return 0; -} - - - -static int CheckItemWithIntLabel(QCBORDecodeContext *pCtx, uint8_t uDataType, uint8_t uNestingLevel, uint8_t uNextNest, int64_t nLabel, QCBORItem *pItem) -{ - QCBORItem Item; - int nCBORError; - - if((nCBORError = QCBORDecode_GetNext(pCtx, &Item))) return -1; - if(Item.uDataType != uDataType) return -1; - if(uNestingLevel > 0) { - if(Item.uLabelType != QCBOR_TYPE_INT64 && Item.uLabelType != QCBOR_TYPE_UINT64) return -1; - if(Item.uLabelType == QCBOR_TYPE_INT64) { - if(Item.label.int64 != nLabel) return -1; - } else { - if(Item.label.uint64 != (uint64_t)nLabel) return -1; - } - } - if(Item.uNestingLevel != uNestingLevel) return -1; - if(Item.uNextNestLevel != uNextNest) return -1; - - if(pItem) { - *pItem = Item; - } - return 0; -} - - -// Same code checks definite and indefinite length versions of the map -static int CheckCSRMaps(QCBORDecodeContext *pDC) -{ - if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_MAP, 0, 1, 0, NULL)) return -1; - - if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_MAP, 1, 2, -23, NULL)) return -1; - - if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_MAP, 2, 3, -20, NULL)) return -1; - - if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_TEXT_STRING, 3, 3, -18, NULL)) return -1; - if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_TEXT_STRING, 3, 3, -17, NULL)) return -1; - if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_TEXT_STRING, 3, 3, -15, NULL)) return -1; - if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_TEXT_STRING, 3, 3, -16, NULL)) return -1; - if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_TEXT_STRING, 3, 2, -14, NULL)) return -1; - - if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_MAP, 2, 3, -19, NULL)) return -1; - if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_MAP, 3, 4, -11, NULL)) return -1; - - if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_INT64, 4, 3, -9, NULL)) return -1; - if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_BYTE_STRING, 3, 1, -10, NULL)) return -1; - - if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_MAP, 1, 2, -22, NULL)) return -1; - if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_INT64, 2, 0, -5, NULL)) return -1; - - if(QCBORDecode_Finish(pDC)) return -2; - - return 0; -} - - -/* -// cbor.me decoded output -{ - -23: { - -20: { - -18: "Organization", - -17: "SSG", - -15: "Confusion", - -16: "San Diego", - -14: "US" - }, - -19: { - -11: { - -9: -7 - }, - -10: '\u0001\u0002\u0003\u0004\u0005\u0006\a\b\t\n' - } - }, - -22: { - -5: -3 - } -} - */ - - -static uint8_t spCSRInput[] = { - 0xa2, 0x36, 0xa2, 0x33, 0xa5, 0x31, 0x6c, 0x4f, - 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x30, 0x63, 0x53, 0x53, 0x47, - 0x2e, 0x69, 0x43, 0x6f, 0x6e, 0x66, 0x75, 0x73, - 0x69, 0x6f, 0x6e, 0x2f, 0x69, 0x53, 0x61, 0x6e, - 0x20, 0x44, 0x69, 0x65, 0x67, 0x6f, 0x2d, 0x62, - 0x55, 0x53, 0x32, 0xa2, 0x2a, 0xa1, 0x28, 0x26, - 0x29, 0x4a, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, - 0x07, 0x08, 0x09, 0x0a, 0x35, 0xa1, 0x24, 0x22}; - -int NestedMapTest() -{ - QCBORDecodeContext DCtx; - - QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spCSRInput), QCBOR_DECODE_MODE_NORMAL); - - return CheckCSRMaps(&DCtx); -} - - - -int StringDecoderModeFailTest() -{ - QCBORDecodeContext DCtx; - - QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spCSRInput), QCBOR_DECODE_MODE_MAP_STRINGS_ONLY); - - QCBORItem Item; - QCBORError nCBORError; - - if(QCBORDecode_GetNext(&DCtx, &Item)) { - return -1; - } - if(Item.uDataType != QCBOR_TYPE_MAP) { - return -2; - } - - nCBORError = QCBORDecode_GetNext(&DCtx, &Item); - if(nCBORError != QCBOR_ERR_MAP_LABEL_TYPE) { - return -3; - } - - return 0; -} - - -// Same map as above, but using indefinite lengths -static uint8_t spCSRInputIndefLen[] = { - 0xbf, 0x36, 0xbf, 0x33, 0xbf, 0x31, 0x6c, 0x4f, - 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x30, 0x63, 0x53, 0x53, 0x47, - 0x2e, 0x69, 0x43, 0x6f, 0x6e, 0x66, 0x75, 0x73, - 0x69, 0x6f, 0x6e, 0x2f, 0x69, 0x53, 0x61, 0x6e, - 0x20, 0x44, 0x69, 0x65, 0x67, 0x6f, 0x2d, 0x62, - 0x55, 0x53, 0xff, 0x32, 0xbf, 0x2a, 0xbf, 0x28, - 0x26, 0xff, 0x29, 0x4a, 0x01, 0x02, 0x03, 0x04, - 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0xff, 0xff, - 0x35, 0xbf, 0x24, 0x22, 0xff, 0xff}; - -int NestedMapTestIndefLen() -{ - QCBORDecodeContext DCtx; - - QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spCSRInputIndefLen), QCBOR_DECODE_MODE_NORMAL); - - return CheckCSRMaps(&DCtx); -} - - - -static UsefulBufC make_nested_indefinite_arrays(int n, UsefulBuf Storage) -{ - UsefulOutBuf UOB; - UsefulOutBuf_Init(&UOB, Storage); - - int i; - for(i = 0; i < n; i++) { - UsefulOutBuf_AppendByte(&UOB, 0x9f); - } - - for(i = 0; i < n; i++) { - UsefulOutBuf_AppendByte(&UOB, 0xff); - } - return UsefulOutBuf_OutUBuf(&UOB); -} - - -static int parse_indeflen_nested(UsefulBufC Nested, int nNestLevel) -{ - QCBORDecodeContext DC; - QCBORDecode_Init(&DC, Nested, 0); - - int j; - for(j = 0; j < nNestLevel; j++) { - QCBORItem Item; - int nReturn = QCBORDecode_GetNext(&DC, &Item); - if(j >= QCBOR_MAX_ARRAY_NESTING) { - // Should be in error - if(nReturn != QCBOR_ERR_ARRAY_NESTING_TOO_DEEP) { - return -4; - } else { - return 0; // Decoding doesn't recover after an error - } - } else { - // Should be no error - if(nReturn) { - return -9; // Should not have got an error - } - } - if(Item.uDataType != QCBOR_TYPE_ARRAY) { - return -7; - } - } - int nReturn = QCBORDecode_Finish(&DC); - if(nReturn) { - return -3; - } - return 0; -} - - -int IndefiniteLengthNestTest() -{ - UsefulBuf_MAKE_STACK_UB(Storage, 50); - int i; - for(i=1; i < QCBOR_MAX_ARRAY_NESTING+4; i++) { - const UsefulBufC Nested = make_nested_indefinite_arrays(i, Storage); - int nReturn = parse_indeflen_nested(Nested, i); - if(nReturn) { - return nReturn; - } - } - return 0; -} - - - -static const uint8_t spIndefiniteArray[] = {0x9f, 0x01, 0x82, 0x02, 0x03, 0xff}; // [1, [2, 3]] -static const uint8_t spIndefiniteArrayBad1[] = {0x9f}; // No closing break -static const uint8_t spIndefiniteArrayBad2[] = {0x9f, 0x9f, 0x02, 0xff}; // Not enough closing breaks -static const uint8_t spIndefiniteArrayBad3[] = {0x9f, 0x02, 0xff, 0xff}; // Too many closing breaks -static const uint8_t spIndefiniteArrayBad4[] = {0x81, 0x9f}; // Unclosed indeflen inside def len -static const uint8_t spIndefiniteArrayBad5[] = {0x9f, 0xd1, 0xff}; // confused tag - -int IndefiniteLengthArrayMapTest() -{ - int nResult; - // --- first test ----- - UsefulBufC IndefLen = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteArray); - - // Decode it and see if it is OK - UsefulBuf_MAKE_STACK_UB(MemPool, 150); - QCBORDecodeContext DC; - QCBORItem Item; - QCBORDecode_Init(&DC, IndefLen, QCBOR_DECODE_MODE_NORMAL); - - QCBORDecode_SetMemPool(&DC, MemPool, false); - - QCBORDecode_GetNext(&DC, &Item); - - if(Item.uDataType != QCBOR_TYPE_ARRAY || - Item.uNestingLevel != 0 || - Item.uNextNestLevel != 1) { - return -111; - } - - QCBORDecode_GetNext(&DC, &Item); - if(Item.uDataType != QCBOR_TYPE_INT64 || - Item.uNestingLevel != 1 || - Item.uNextNestLevel != 1) { - return -2; - } - - QCBORDecode_GetNext(&DC, &Item); - if(Item.uDataType != QCBOR_TYPE_ARRAY || - Item.uNestingLevel != 1 || - Item.uNextNestLevel != 2) { - return -3; - } - - QCBORDecode_GetNext(&DC, &Item); - if(Item.uDataType != QCBOR_TYPE_INT64 || - Item.uNestingLevel != 2 || - Item.uNextNestLevel != 2) { - return -4; - } - - QCBORDecode_GetNext(&DC, &Item); - if(Item.uDataType != QCBOR_TYPE_INT64 || - Item.uNestingLevel != 2 || - Item.uNextNestLevel != 0) { - return -5; - } - - if(QCBORDecode_Finish(&DC)) { - return -6; - } - - // --- next test ----- - IndefLen = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteArrayBad1); - - QCBORDecode_Init(&DC, IndefLen, QCBOR_DECODE_MODE_NORMAL); - - QCBORDecode_SetMemPool(&DC, MemPool, false); - - nResult = QCBORDecode_GetNext(&DC, &Item); - if(nResult || Item.uDataType != QCBOR_TYPE_ARRAY) { - return -7; - } - - nResult = QCBORDecode_Finish(&DC); - if(nResult != QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN) { - return -8; - } - - - // --- next test ----- - IndefLen = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteArrayBad2); - - QCBORDecode_Init(&DC, IndefLen, QCBOR_DECODE_MODE_NORMAL); - - QCBORDecode_SetMemPool(&DC, MemPool, false); - - nResult = QCBORDecode_GetNext(&DC, &Item); - if(nResult || Item.uDataType != QCBOR_TYPE_ARRAY) { - return -9; - } - - nResult = QCBORDecode_GetNext(&DC, &Item); - if(nResult || Item.uDataType != QCBOR_TYPE_ARRAY) { - return -10; - } - - nResult = QCBORDecode_GetNext(&DC, &Item); - if(nResult || Item.uDataType != QCBOR_TYPE_INT64) { - return -11; - } - - nResult = QCBORDecode_Finish(&DC); - if(nResult != QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN) { - return -12; - } - - - // --- next test ----- - IndefLen = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteArrayBad3); - - QCBORDecode_Init(&DC, IndefLen, QCBOR_DECODE_MODE_NORMAL); - - QCBORDecode_SetMemPool(&DC, MemPool, false); - - nResult = QCBORDecode_GetNext(&DC, &Item); - if(nResult || Item.uDataType != QCBOR_TYPE_ARRAY) { - return -13; - } - - nResult = QCBORDecode_GetNext(&DC, &Item); - if(nResult != QCBOR_ERR_BAD_BREAK) { - return -14; - } - - - // --- next test ----- - IndefLen = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteArrayBad4); - - QCBORDecode_Init(&DC, IndefLen, QCBOR_DECODE_MODE_NORMAL); - - QCBORDecode_SetMemPool(&DC, MemPool, false); - - nResult = QCBORDecode_GetNext(&DC, &Item); - if(nResult || Item.uDataType != QCBOR_TYPE_ARRAY) { - return -15; - } - - nResult = QCBORDecode_GetNext(&DC, &Item); - if(nResult || Item.uDataType != QCBOR_TYPE_ARRAY) { - return -16; - } - - nResult = QCBORDecode_Finish(&DC); - if(nResult != QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN) { - return -17; - } - - // --- next test ----- - IndefLen = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteArrayBad5); - - QCBORDecode_Init(&DC, IndefLen, QCBOR_DECODE_MODE_NORMAL); - - QCBORDecode_SetMemPool(&DC, MemPool, false); - - nResult = QCBORDecode_GetNext(&DC, &Item); - if(nResult || Item.uDataType != QCBOR_TYPE_ARRAY) { - return -18; - } - - nResult = QCBORDecode_GetNext(&DC, &Item); - if(nResult != QCBOR_ERR_BAD_BREAK) { - return -19; - } - - return 0; -} - - -static const uint8_t spIndefiniteLenString[] = { - 0x81, // Array of length one - 0x7f, // text string marked with indefinite length - 0x65, 0x73, 0x74, 0x72, 0x65, 0x61, // first segment - 0x64, 0x6d, 0x69, 0x6e, 0x67, // second segment - 0xff // ending break -}; - -static const uint8_t spIndefiniteLenStringBad2[] = { - 0x81, // Array of length one - 0x7f, // text string marked with indefinite length - 0x65, 0x73, 0x74, 0x72, 0x65, 0x61, // first segment - 0x44, 0x6d, 0x69, 0x6e, 0x67, // second segment of wrong type - 0xff // ending break -}; - -static const uint8_t spIndefiniteLenStringBad3[] = { - 0x81, // Array of length one - 0x7f, // text string marked with indefinite length - 0x01, 0x02, // Not a string - 0xff // ending break -}; - -static const uint8_t spIndefiniteLenStringBad4[] = { - 0x81, // Array of length one - 0x7f, // text string marked with indefinite length - 0x65, 0x73, 0x74, 0x72, 0x65, 0x61, // first segment - 0x64, 0x6d, 0x69, 0x6e, 0x67, // second segment - // missing end of string -}; - -static const uint8_t spIndefiniteLenStringLabel[] = { - 0xa1, // Array of length one - 0x7f, // text string marked with indefinite length - 0x65, 0x73, 0x74, 0x72, 0x75, 0x75, // first segment - 0x64, 0x6d, 0x69, 0x6e, 0x67, // second segment - 0xff, // ending break - 0x01 // integer being labeled. -}; - -static UsefulBufC MakeIndefiniteBigBstr(UsefulBuf Storage) // TODO: size this -{ - UsefulOutBuf UOB; - - UsefulOutBuf_Init(&UOB, Storage); - UsefulOutBuf_AppendByte(&UOB, 0x81); - UsefulOutBuf_AppendByte(&UOB, 0x5f); - - int i = 0; - for(int nChunkSize = 1; nChunkSize <= 128; nChunkSize *= 2) { - UsefulOutBuf_AppendByte(&UOB, 0x58); - UsefulOutBuf_AppendByte(&UOB, (uint8_t)nChunkSize); - for(int j = 0; j < nChunkSize; j++ ) { - UsefulOutBuf_AppendByte(&UOB, i); - i++; - } - } - UsefulOutBuf_AppendByte(&UOB, 0xff); - - return UsefulOutBuf_OutUBuf(&UOB); -} - -static int CheckBigString(UsefulBufC BigString) -{ - if(BigString.len != 255) { - return 1; - } - - for(uint8_t i = 0; i < 255; i++){ - if(((const uint8_t *)BigString.ptr)[i] != i) { - return 1; - } - } - return 0; -} - - -int IndefiniteLengthStringTest() -{ - QCBORDecodeContext DC; - QCBORItem Item; - // big enough for MakeIndefiniteBigBstr() + MemPool overhead - UsefulBuf_MAKE_STACK_UB(MemPool, 350); - - // --- Simple normal indefinite length string ------ - UsefulBufC IndefLen = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteLenString); - QCBORDecode_Init(&DC, IndefLen, QCBOR_DECODE_MODE_NORMAL); - - if(QCBORDecode_SetMemPool(&DC, MemPool, false)) { - return -1; - } - - if(QCBORDecode_GetNext(&DC, &Item)) { - return -2; - } - if(Item.uDataType != QCBOR_TYPE_ARRAY || Item.uDataAlloc) { - return -3; - } - - if(QCBORDecode_GetNext(&DC, &Item)) { - return -4; - } - if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || !Item.uDataAlloc) { - return -5; - } - if(QCBORDecode_Finish(&DC)) { - return -6; - } - - // ----- types mismatch --- - QCBORDecode_Init(&DC, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteLenStringBad2), QCBOR_DECODE_MODE_NORMAL); - - if(QCBORDecode_SetMemPool(&DC, MemPool, false)) { - return -7; - } - - if(QCBORDecode_GetNext(&DC, &Item)) { - return -8; - } - if(Item.uDataType != QCBOR_TYPE_ARRAY) { - return -9; - } - - if(QCBORDecode_GetNext(&DC, &Item) != QCBOR_ERR_INDEFINITE_STRING_CHUNK) { - return -10; - } - - // ----- not a string --- - QCBORDecode_Init(&DC, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteLenStringBad3), QCBOR_DECODE_MODE_NORMAL); - - if(QCBORDecode_SetMemPool(&DC, MemPool, false)) { - return -11; - } - - if(QCBORDecode_GetNext(&DC, &Item)) { - return -12; - } - if(Item.uDataType != QCBOR_TYPE_ARRAY) { - return -13; - } - - if(QCBORDecode_GetNext(&DC, &Item) != QCBOR_ERR_INDEFINITE_STRING_CHUNK) { - return -14; - } - - // ----- no end ----- - QCBORDecode_Init(&DC, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteLenStringBad4), QCBOR_DECODE_MODE_NORMAL); - - if(QCBORDecode_SetMemPool(&DC, MemPool, false)) { - return -15; - } - - if(QCBORDecode_GetNext(&DC, &Item)) { - return -16; - } - if(Item.uDataType != QCBOR_TYPE_ARRAY) { - return -17; - } - - if(QCBORDecode_GetNext(&DC, &Item) != QCBOR_ERR_HIT_END) { - return -18; - } - - // ------ Don't set a string allocator and see an error ----- - QCBORDecode_Init(&DC, IndefLen, QCBOR_DECODE_MODE_NORMAL); - - QCBORDecode_GetNext(&DC, &Item); - if(Item.uDataType != QCBOR_TYPE_ARRAY) { - return -19; - } - - if(QCBORDecode_GetNext(&DC, &Item) != QCBOR_ERR_NO_STRING_ALLOCATOR) { - return -20; - } - - // ----- Mempool is way too small ----- - UsefulBuf_MAKE_STACK_UB(MemPoolTooSmall, 20); // 20 is too small no matter what - - QCBORDecode_Init(&DC, IndefLen, QCBOR_DECODE_MODE_NORMAL); - if(!QCBORDecode_SetMemPool(&DC, MemPoolTooSmall, false)) { - return -21; - } - - // ----- Mempool is way too small ----- - UsefulBuf_MAKE_STACK_UB(BigIndefBStrStorage, 290); - const UsefulBufC BigIndefBStr = MakeIndefiniteBigBstr(BigIndefBStrStorage); - - UsefulBuf_MAKE_STACK_UB(MemPoolSmall, 80); // 80 is big enough for MemPool overhead, but not BigIndefBStr - - QCBORDecode_Init(&DC, BigIndefBStr, QCBOR_DECODE_MODE_NORMAL); - if(QCBORDecode_SetMemPool(&DC, MemPoolSmall, false)) { - return -22; - } - - QCBORDecode_GetNext(&DC, &Item); - if(Item.uDataType != QCBOR_TYPE_ARRAY) { - return -23; - } - if(QCBORDecode_GetNext(&DC, &Item) != QCBOR_ERR_STRING_ALLOCATE) { - return -24; - } - - // ---- big bstr ----- - QCBORDecode_Init(&DC, BigIndefBStr, QCBOR_DECODE_MODE_NORMAL); - - if(QCBORDecode_SetMemPool(&DC, MemPool, false)) { - return -25; - } - - if(QCBORDecode_GetNext(&DC, &Item)) { - return -26; - } - if(Item.uDataType != QCBOR_TYPE_ARRAY || Item.uDataAlloc) { - return -26; - } - - if(QCBORDecode_GetNext(&DC, &Item)) { - return -27; - } - if(Item.uDataType != QCBOR_TYPE_BYTE_STRING || !Item.uDataAlloc || Item.uNestingLevel != 1) { - return -28; - } - if(CheckBigString(Item.val.string)) { - return -3; - } - if(QCBORDecode_Finish(&DC)) { - return -29; - } - - // --- label is an indefinite length string ------ - QCBORDecode_Init(&DC, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteLenStringLabel), QCBOR_DECODE_MODE_NORMAL); - - if(QCBORDecode_SetMemPool(&DC, MemPool, false)) { - return -30; - } - - QCBORDecode_GetNext(&DC, &Item); - if(Item.uDataType != QCBOR_TYPE_MAP) { - return -31; - } - - if(QCBORDecode_GetNext(&DC, &Item)){ - return -32; - } - if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || Item.uDataType != QCBOR_TYPE_INT64 || - Item.uDataAlloc || !Item.uLabelAlloc || - UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("struuming"))) { - return -33; - } - - if(QCBORDecode_Finish(&DC)) { - return -34; - } - - return 0; -} - - -int AllocAllStringsTest() -{ - QCBORDecodeContext DC; - QCBORError nCBORError; - - - // First test, use the "CSRMap" as easy input and checking - QCBORDecode_Init(&DC, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spCSRInput), QCBOR_DECODE_MODE_NORMAL); - - UsefulBuf_MAKE_STACK_UB(Pool, sizeof(spCSRInput) + QCBOR_DECODE_MIN_MEM_POOL_SIZE); - - nCBORError = QCBORDecode_SetMemPool(&DC, Pool, 1); // Turn on copying. - if(nCBORError) { - return -1; - } - - if(CheckCSRMaps(&DC)) { - return -2; - } - - // Next parse, save pointers to a few strings, destroy original and see all is OK. - UsefulBuf_MAKE_STACK_UB(CopyOfStorage, sizeof(pValidMapEncoded) + QCBOR_DECODE_MIN_MEM_POOL_SIZE); - const UsefulBufC CopyOf = UsefulBuf_Copy(CopyOfStorage, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded)); - - QCBORDecode_Init(&DC, CopyOf, QCBOR_DECODE_MODE_NORMAL); - UsefulBuf_Set(Pool, '/'); - QCBORDecode_SetMemPool(&DC, Pool, 1); // Turn on copying. - - QCBORItem Item1, Item2, Item3, Item4; - if((nCBORError = QCBORDecode_GetNext(&DC, &Item1))) - return nCBORError; - if(Item1.uDataType != QCBOR_TYPE_MAP || - Item1.val.uCount != 3) - return -3; - if((nCBORError = QCBORDecode_GetNext(&DC, &Item1))) - return nCBORError; - if((nCBORError = QCBORDecode_GetNext(&DC, &Item2))) - return nCBORError; - if((nCBORError = QCBORDecode_GetNext(&DC, &Item3))) - return nCBORError; - if((nCBORError = QCBORDecode_GetNext(&DC, &Item4))) - return nCBORError; - - UsefulBuf_Set(CopyOfStorage, '_'); - - if(Item1.uLabelType != QCBOR_TYPE_TEXT_STRING || - Item1.uDataType != QCBOR_TYPE_INT64 || - Item1.val.int64 != 42 || - UsefulBuf_Compare(Item1.label.string, UsefulBuf_FromSZ("first integer"))) { - return -4; - } - - - if(Item2.uLabelType != QCBOR_TYPE_TEXT_STRING || - UsefulBuf_Compare(Item2.label.string, UsefulBuf_FromSZ("an array of two strings")) || - Item2.uDataType != QCBOR_TYPE_ARRAY || - Item2.val.uCount != 2) - return -5; - - if(Item3.uDataType != QCBOR_TYPE_TEXT_STRING || - UsefulBuf_Compare(Item3.val.string, UsefulBuf_FromSZ("string1"))) { - return -6; - } - - if(Item4.uDataType != QCBOR_TYPE_TEXT_STRING || - UsefulBuf_Compare(Item4.val.string, UsefulBuf_FromSZ("string2"))) { - return -7; - } - - // Next parse with a pool that is too small - UsefulBuf_MAKE_STACK_UB(SmallPool, QCBOR_DECODE_MIN_MEM_POOL_SIZE + 1); - QCBORDecode_Init(&DC, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded), QCBOR_DECODE_MODE_NORMAL); - QCBORDecode_SetMemPool(&DC, SmallPool, 1); // Turn on copying. - if((nCBORError = QCBORDecode_GetNext(&DC, &Item1))) - return -8; - if(Item1.uDataType != QCBOR_TYPE_MAP || - Item1.val.uCount != 3) { - return -9; - } - if(!(nCBORError = QCBORDecode_GetNext(&DC, &Item1))){ - if(!(nCBORError = QCBORDecode_GetNext(&DC, &Item2))) { - if(!(nCBORError = QCBORDecode_GetNext(&DC, &Item3))) { - nCBORError = QCBORDecode_GetNext(&DC, &Item4); - } - } - } - if(nCBORError != QCBOR_ERR_STRING_ALLOCATE) { - return -10; - } - - return 0; -} - -// Cheating declaration to get to the special test hook -size_t MemPoolTestHook_GetPoolSize(void *ctx); - - -int MemPoolTest(void) -{ - // Set up the decoder with a tiny bit of CBOR to parse - QCBORDecodeContext DC; - const uint8_t pMinimalCBOR[] = {0xa0}; // One empty map - QCBORDecode_Init(&DC, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pMinimalCBOR),0); - - // Set up an memory pool of 100 bytes - UsefulBuf_MAKE_STACK_UB(Pool, 100); - QCBORError nError = QCBORDecode_SetMemPool(&DC, Pool, 0); - if(nError) { - return -9; - } - - // Cheat a little to get to the string allocator object - // so we can call it directly to test it - QCBORStringAllocator *pAlloc = (QCBORStringAllocator *)DC.pStringAllocator; - // Cheat some more to know exactly the - size_t uAvailPool = MemPoolTestHook_GetPoolSize(pAlloc); - - // First test -- ask for too much in one go - UsefulBuf Allocated = (*pAlloc->fAllocate)(pAlloc->pAllocaterContext, NULL, uAvailPool+1); - if(!UsefulBuf_IsNULL(Allocated)) { - return -1; - } - - - // Re do the set up for the next test that will do a successful alloc, - // a fail, a free and then success - // This test should work on 32 and 64-bit machines if the compiler - // does the expected thing with pointer sizes for the internal - // MemPool implementation leaving 44 or 72 bytes of pool memory. - QCBORDecode_SetMemPool(&DC, Pool, 0); - - // Cheat a little to get to the string allocator object - // so we can call it directly to test it - pAlloc = (QCBORStringAllocator *)DC.pStringAllocator; - // Cheat some more to know exactly the - uAvailPool = MemPoolTestHook_GetPoolSize(pAlloc); - - Allocated = (*pAlloc->fAllocate)(pAlloc->pAllocaterContext, NULL, uAvailPool-1); - if(UsefulBuf_IsNULL(Allocated)) { // expected to succeed - return -2; - } - UsefulBuf Allocated2 = (*pAlloc->fAllocate)(pAlloc->pAllocaterContext, NULL, uAvailPool/2); - if(!UsefulBuf_IsNULL(Allocated2)) { // expected to fail - return -3; - } - (*pAlloc->fFree)(pAlloc->pAllocaterContext, Allocated.ptr); - Allocated = (*pAlloc->fAllocate)(pAlloc->pAllocaterContext, NULL, uAvailPool/2); - if(UsefulBuf_IsNULL(Allocated)) { // succeed because of the free - return -4; - } - - - // Re do set up for next test that involves a successful alloc, - // and a successful realloc and a failed realloc - QCBORDecode_SetMemPool(&DC, Pool, 0); - - // Cheat a little to get to the string allocator object - // so we can call it directly to test it - pAlloc = (QCBORStringAllocator *)DC.pStringAllocator; - Allocated = (*pAlloc->fAllocate)(pAlloc->pAllocaterContext, NULL, uAvailPool/2); - if(UsefulBuf_IsNULL(Allocated)) { // expected to succeed - return -5; - } - Allocated2 = (*pAlloc->fAllocate)(pAlloc->pAllocaterContext, Allocated.ptr, uAvailPool); - if(UsefulBuf_IsNULL(Allocated2)) { - return -6; - } - if(Allocated2.ptr != Allocated.ptr || Allocated2.len != uAvailPool) { - return -7; - } - UsefulBuf Allocated3 = (*pAlloc->fAllocate)(pAlloc->pAllocaterContext, Allocated.ptr, uAvailPool+1); - if(!UsefulBuf_IsNULL(Allocated3)) { // expected to fail - return -8; - } - - return 0; -} - diff --git a/components/TARGET_PSA/services/attestation/qcbor/test/qcbor_decode_tests.h b/components/TARGET_PSA/services/attestation/qcbor/test/qcbor_decode_tests.h deleted file mode 100644 index cbd352e..0000000 --- a/components/TARGET_PSA/services/attestation/qcbor/test/qcbor_decode_tests.h +++ /dev/null @@ -1,230 +0,0 @@ -/*============================================================================== - Copyright (c) 2016-2018, The Linux Foundation. - Copyright (c) 2018-2019, Laurence Lundblade. - All rights reserved. - SPDX-License-Identifier: BSD-3-Clause - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of The Linux Foundation nor the names of its - contributors, nor the name "Laurence Lundblade" may be used to - endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED -WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT -ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS -BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE -OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN -IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ==============================================================================*/ - -#ifndef __QCBOR__qcbort_decode_tests__ -#define __QCBOR__qcbort_decode_tests__ - -#include "qcbor.h" - - -/* - Notes: - - - All the functions in qcbor.h are called once in the aggregation of all the tests below. - - - All the types that are supported are given as input and parsed by these tests - - - There is some hostile input such as invalid lengths and CBOR too complex - and types this parser doesn't handle - - */ - - - - -/* - Parse a well-known set of integers including those around the boundaries and - make sure the expected values come out - */ -int IntegerValuesParseTest(void); - - - - - -/* - Decode a simple CBOR encoded array and make sure it returns all the correct values. - This is a decode test. - */ -int SimpleArrayTest(void); - - -/* - Make sure a maximally deep array can be parsed and that the - reported nesting level is correct. This uses test vector - of CBOR encoded data with a depth of 10. This a parse test. - */ -int ParseDeepArrayTest(void); - - -/* - See that the correct error is reported when parsing - an array of depth 11, one too large. - */ -int ParseTooDeepArrayTest(void); - - -/* - Try to parse some legit CBOR types that this parsers - doesn't support. - */ -int UnsupportedCBORDecodeTest(void); - - -/* - This takes the encoded CBOR integers used in the above test and parses - it over and over with one more byte less each time. It should fail - every time on incorrect CBOR input. This is a hostile input decode test. - */ -int ShortBufferParseTest(void); - - -/* - Same as ShortBufferParseTest, but with a different encoded CBOR input. - It is another hostile input test - */ -int ShortBufferParseTest2(void); - - -/* - Parses the somewhat complicated CBOR MAP and makes sure all the correct - values parse out. About 15 values are tested. This is a decode test. - */ -int ParseMapTest(void); - - - -int FloatValuesTest1(void); - - - -int SimpleValuesTest1(void); - - -/* - - */ -int ParseMapAsArrayTest(void); - - - -int ParseSimpleTest(void); - - - -/* - Tests a number of failure cases on bad CBOR to get the right error code - */ -int FailureTests(void); - - -/* - Parses all possible inputs that are two bytes long. Main point - is that the test doesn't crash as it doesn't evaluate the - input for correctness in any way. - - (Parsing all possible 3 byte strings takes too long on all but - very fast machines). - */ -int ComprehensiveInputTest(void); - - -/* - Parses all possible inputs that are four bytes long. Main point - is that the test doesn't crash as it doesn't evaluate the - input for correctness in any way. This runs very slow, so it - is only practical as a once-in-a-while regression test on - fast machines. - */ -int BigComprehensiveInputTest(void); - - -/* - Thest the date types -- epoch and strings - */ -int DateParseTest(void); - - -/* - Test optional tags like the CBOR magic number. - */ -int OptTagParseTest(void); - - -/* - Parse some big numbers, positive and negative - */ -int BignumParseTest(void); - - -int StringDecoderModeFailTest(void); - - -/* - Parse some nested maps - */ -int NestedMapTest(void); - - -/* - Parse maps with indefinite lengths - */ -int NestedMapTestIndefLen(void); - - -/* - Parse some maps and arrays with indefinite lengths. - Includes some error cases. - */ -int IndefiniteLengthArrayMapTest(void); - - -/* - Parse indefinite length strings. Uses - MemPool. Includes error cases. - */ -int IndefiniteLengthStringTest(void); - - -/* - Test deep nesting of indefinite length - maps and arrays including too deep. - */ -int IndefiniteLengthNestTest(void); - - -/* - Test parsing strings were all strings, not - just indefinite length strings, are - allocated. Includes error test cases. - */ -int AllocAllStringsTest(void); - - -/* - Direct test of MemPool string allocator - */ -int MemPoolTest(void); - - -#endif /* defined(__QCBOR__qcbort_decode_tests__) */ diff --git a/components/TARGET_PSA/services/attestation/qcbor/test/qcbor_encode_tests.c b/components/TARGET_PSA/services/attestation/qcbor/test/qcbor_encode_tests.c deleted file mode 100644 index ca46460..0000000 --- a/components/TARGET_PSA/services/attestation/qcbor/test/qcbor_encode_tests.c +++ /dev/null @@ -1,2008 +0,0 @@ -/*============================================================================== - Copyright (c) 2016-2018, The Linux Foundation. - Copyright (c) 2018-2019, Laurence Lundblade. - All rights reserved. - SPDX-License-Identifier: BSD-3-Clause - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of The Linux Foundation nor the names of its - contributors, nor the name "Laurence Lundblade" may be used to - endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED -WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT -ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS -BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE -OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN -IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ==============================================================================*/ - -#include "qcbor.h" -#include "qcbor_encode_tests.h" - - -/* - This is the test set for CBOR encoding. - - This is largely complete for the implemented. - - A few more things to do include: - - Add a test for counting the top level items and adding it back in with AddRaw() - - Run on some different CPUs like 32-bit and maybe even 16-bit - - Test the large array count limit - - Add the CBOR diagnostic output for every expected - - */ - -//#define PRINT_FUNCTIONS_FOR_DEBUGGINGXX - -#ifdef PRINT_FUNCTIONS_FOR_DEBUGGINGXX -#include - -// ifdef these out to not have compiler warnings -static void printencoded(const uint8_t *pEncoded, size_t nLen) -{ - size_t i; - for(i = 0; i < nLen; i++) { - uint8_t Z = pEncoded[i]; - printf("%02x ", Z); - } - printf("\n"); - - fflush(stdout); -} - - -// Do the comparison and print out where it fails -static int UsefulBuf_Compare_Print(UsefulBufC U1, UsefulBufC U2) { - size_t i; - for(i = 0; i < U1.len; i++) { - if(((uint8_t *)U1.ptr)[i] != ((uint8_t *)U2.ptr)[i]) { - printf("Position: %d Actual: 0x%x Expected: 0x%x\n", i, ((uint8_t *)U1.ptr)[i], ((uint8_t *)U2.ptr)[i]); - return 1; - } - } - return 0; - -} - -#define CheckResults(Enc, Expected) \ - UsefulBuf_Compare_Print(Enc, (UsefulBufC){Expected, sizeof(Expected)}) - -#else - -#define CheckResults(Enc, Expected) \ - UsefulBuf_Compare(Enc, (UsefulBufC){Expected, sizeof(Expected)}) - -#endif - - - -// One big buffer that is used by all the tests to encode into -// Putting it in uninitialized data is better than using a lot -// of stack. The tests should run on small devices too. -static uint8_t spBigBuf[2200]; - - - -/* - Some very minimal tests. - */ -int BasicEncodeTest() -{ - // Very simple CBOR, a map with one boolean that is true in it - QCBOREncodeContext EC; - - QCBOREncode_Init(&EC, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf)); - - QCBOREncode_OpenMap(&EC); - QCBOREncode_AddBoolToMapN(&EC, 66, true); - QCBOREncode_CloseMap(&EC); - - UsefulBufC Encoded; - if(QCBOREncode_Finish(&EC, &Encoded)) { - return -1; - } - - - // Decode it and see that is right - QCBORDecodeContext DC; - QCBORItem Item; - QCBORDecode_Init(&DC, Encoded, QCBOR_DECODE_MODE_NORMAL); - - QCBORDecode_GetNext(&DC, &Item); - if(Item.uDataType != QCBOR_TYPE_MAP) { - return -2; - } - - QCBORDecode_GetNext(&DC, &Item); - if(Item.uDataType != QCBOR_TYPE_TRUE) { - return -3; - } - - if(QCBORDecode_Finish(&DC)) { - return -4; - } - - - // Make another encoded message with the CBOR from the previous put into this one - UsefulBuf_MAKE_STACK_UB(MemoryForEncoded2, 20); - QCBOREncode_Init(&EC, MemoryForEncoded2); - QCBOREncode_OpenArray(&EC); - QCBOREncode_AddUInt64(&EC, 451); - QCBOREncode_AddEncoded(&EC, Encoded); - QCBOREncode_OpenMap(&EC); - QCBOREncode_AddEncodedToMapN(&EC, -70000, Encoded); - QCBOREncode_CloseMap(&EC); - QCBOREncode_CloseArray(&EC); - - UsefulBufC Encoded2; - if(QCBOREncode_Finish(&EC, &Encoded2)) { - return -5; - } - /* - [ // 0 1:3 - 451, // 1 1:2 - { // 1 1:2 2:1 - 66: true // 2 1:1 - }, - { // 1 1:1 2:1 - -70000: { // 2 1:1 2:1 3:1 - 66: true // 3 XXXXXX - } - } - ] - - - - 83 # array(3) - 19 01C3 # unsigned(451) - A1 # map(1) - 18 42 # unsigned(66) - F5 # primitive(21) - A1 # map(1) - 3A 0001116F # negative(69999) - A1 # map(1) - 18 42 # unsigned(66) - F5 # primitive(21) - */ - - // Decode it and see if it is OK - QCBORDecode_Init(&DC, Encoded2, QCBOR_DECODE_MODE_NORMAL); - - // 0 1:3 - QCBORDecode_GetNext(&DC, &Item); - if(Item.uDataType != QCBOR_TYPE_ARRAY || Item.val.uCount != 3) { - return -6; - } - - // 1 1:2 - QCBORDecode_GetNext(&DC, &Item); - if(Item.uDataType != QCBOR_TYPE_INT64 || Item.val.uint64 != 451) { - return -7; - } - - // 1 1:2 2:1 - QCBORDecode_GetNext(&DC, &Item); - if(Item.uDataType != QCBOR_TYPE_MAP || Item.val.uCount != 1) { - return -8; - } - - // 2 1:1 - QCBORDecode_GetNext(&DC, &Item); - if(Item.uDataType != QCBOR_TYPE_TRUE) { - return -9; - } - - // 1 1:1 2:1 - QCBORDecode_GetNext(&DC, &Item); - if(Item.uDataType != QCBOR_TYPE_MAP || Item.val.uCount != 1) { - return -10; - } - - // 2 1:1 2:1 3:1 - QCBORDecode_GetNext(&DC, &Item); - if(Item.uDataType != QCBOR_TYPE_MAP || Item.val.uCount != 1 || Item.uLabelType != QCBOR_TYPE_INT64 || Item.label.int64 != -70000) { - return -11; - } - - // 3 XXXXXX - QCBORDecode_GetNext(&DC, &Item); - if(Item.uDataType != QCBOR_TYPE_TRUE || Item.uLabelType != QCBOR_TYPE_INT64 || Item.label.int64 != 66) { - return -12; - } - - if(QCBORDecode_Finish(&DC)) { - return -13; - } - - return 0; -} - - - -static const uint8_t spExpectedEncodedAll[] = { - 0x98, 0x22, 0x66, 0x55, 0x49, 0x4e, 0x54, 0x36, 0x32, 0xd8, - 0x64, 0x1a, 0x05, 0x5d, 0x23, 0x15, 0x65, 0x49, 0x4e, 0x54, - 0x36, 0x34, 0xd8, 0x4c, 0x1b, 0x00, 0x00, 0x00, 0x12, 0x16, - 0xaf, 0x2b, 0x15, 0x00, 0x38, 0x2b, 0xa4, 0x63, 0x4c, 0x42, - 0x4c, 0x18, 0x4d, 0x23, 0x18, 0x58, 0x78, 0x1a, 0x4e, 0x45, - 0x47, 0x4c, 0x42, 0x4c, 0x54, 0x48, 0x41, 0x54, 0x20, 0x49, - 0x53, 0x20, 0x4b, 0x49, 0x4e, 0x44, 0x20, 0x4f, 0x46, 0x20, - 0x4c, 0x4f, 0x4e, 0x47, 0x3b, 0x00, 0x00, 0x02, 0x2d, 0x9a, - 0xc6, 0x94, 0x55, 0x3a, 0x05, 0xf5, 0xe0, 0xff, 0x3a, 0x2f, - 0xaf, 0x07, 0xff, 0xc1, 0x1a, 0x8e, 0x15, 0x1c, 0x8a, - 0xa3, 0x74, 0x4c, 0x6f, 0x6e, 0x67, 0x4c, 0x69, 0x76, 0x65, - 0x44, 0x65, 0x6e, 0x69, 0x73, 0x52, 0x69, 0x74, 0x63, 0x68, - 0x69, 0x65, 0xc1, 0x1a, 0x53, 0x72, 0x4e, 0x00, 0x66, 0x74, - 0x69, 0x6d, 0x65, 0x28, 0x29, 0xc1, 0x1a, 0x58, 0x0d, 0x41, - 0x72, 0x39, 0x07, 0xb0, 0xc1, 0x1a, 0x58, 0x0d, 0x3f, 0x76, - 0x42, 0xff, 0x00, 0xa3, 0x66, 0x62, 0x69, 0x6e, 0x62, 0x69, - 0x6e, 0xda, 0x00, 0x01, 0x86, 0xa0, 0x41, 0x00, 0x66, 0x62, - 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x43, 0x01, 0x02, 0x03, 0x00, - 0x44, 0x04, 0x02, 0x03, 0xfe, 0x6f, 0x62, 0x61, 0x72, 0x20, - 0x62, 0x61, 0x72, 0x20, 0x66, 0x6f, 0x6f, 0x20, 0x62, 0x61, - 0x72, 0x64, 0x6f, 0x6f, 0x66, 0x0a, 0xd8, 0x20, 0x78, 0x6b, - 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x73, 0x74, 0x61, - 0x63, 0x6b, 0x6f, 0x76, 0x65, 0x72, 0x66, 0x6c, 0x6f, 0x77, - 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x32, 0x38, 0x30, 0x35, 0x39, - 0x36, 0x39, 0x37, 0x2f, 0x68, 0x6f, 0x77, 0x2d, 0x64, 0x6f, - 0x2d, 0x69, 0x2d, 0x74, 0x6f, 0x67, 0x67, 0x6c, 0x65, 0x2d, - 0x62, 0x65, 0x74, 0x77, 0x65, 0x65, 0x6e, 0x2d, 0x64, 0x65, - 0x62, 0x75, 0x67, 0x2d, 0x61, 0x6e, 0x64, 0x2d, 0x72, 0x65, - 0x6c, 0x65, 0x61, 0x73, 0x65, 0x2d, 0x62, 0x75, 0x69, 0x6c, - 0x64, 0x73, 0x2d, 0x69, 0x6e, 0x2d, 0x78, 0x63, 0x6f, 0x64, - 0x65, 0x2d, 0x36, 0x2d, 0x37, 0x2d, 0x38, 0xd8, 0x22, 0x78, - 0x1c, 0x59, 0x57, 0x35, 0x35, 0x49, 0x47, 0x4e, 0x68, 0x63, - 0x6d, 0x35, 0x68, 0x62, 0x43, 0x42, 0x77, 0x62, 0x47, 0x56, - 0x68, 0x63, 0x33, 0x56, 0x79, 0x5a, 0x51, 0x3d, 0x3d, 0xd8, - 0x23, 0x67, 0x5b, 0x5e, 0x61, 0x62, 0x63, 0x5d, 0x2b, 0xd8, - 0x24, 0x79, 0x01, 0x57, 0x4d, 0x49, 0x4d, 0x45, 0x2d, 0x56, - 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x31, 0x2e, - 0x30, 0x0a, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, - 0x54, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x6d, 0x75, 0x6c, 0x74, - 0x69, 0x70, 0x61, 0x72, 0x74, 0x2f, 0x6d, 0x69, 0x78, 0x65, - 0x64, 0x3b, 0x0a, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72, - 0x79, 0x3d, 0x22, 0x58, 0x58, 0x58, 0x58, 0x62, 0x6f, 0x75, - 0x6e, 0x64, 0x61, 0x72, 0x79, 0x20, 0x74, 0x65, 0x78, 0x74, - 0x22, 0x0a, 0x0a, 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, - 0x20, 0x61, 0x20, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x61, - 0x72, 0x74, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x20, 0x69, 0x6e, 0x20, 0x4d, 0x49, 0x4d, 0x45, 0x20, 0x66, - 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x2e, 0x0a, 0x0a, 0x2d, 0x2d, - 0x58, 0x58, 0x58, 0x58, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61, - 0x72, 0x79, 0x20, 0x74, 0x65, 0x78, 0x74, 0x0a, 0x43, 0x6f, - 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x54, 0x79, 0x70, 0x65, - 0x3a, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x70, 0x6c, 0x61, - 0x69, 0x6e, 0x0a, 0x0a, 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, - 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x6f, 0x64, 0x79, - 0x20, 0x74, 0x65, 0x78, 0x74, 0x0a, 0x0a, 0x2d, 0x2d, 0x58, - 0x58, 0x58, 0x58, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72, - 0x79, 0x20, 0x74, 0x65, 0x78, 0x74, 0x0a, 0x43, 0x6f, 0x6e, - 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x54, 0x79, 0x70, 0x65, 0x3a, - 0x20, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x70, 0x6c, 0x61, 0x69, - 0x6e, 0x3b, 0x0a, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, - 0x2d, 0x44, 0x69, 0x73, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, - 0x6f, 0x6e, 0x3a, 0x20, 0x61, 0x74, 0x74, 0x61, 0x63, 0x68, - 0x6d, 0x65, 0x6e, 0x74, 0x3b, 0x0a, 0x66, 0x69, 0x6c, 0x65, - 0x6e, 0x61, 0x6d, 0x65, 0x3d, 0x22, 0x74, 0x65, 0x73, 0x74, - 0x2e, 0x74, 0x78, 0x74, 0x22, 0x0a, 0x0a, 0x74, 0x68, 0x69, - 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, - 0x74, 0x74, 0x61, 0x63, 0x68, 0x6d, 0x65, 0x6e, 0x74, 0x20, - 0x74, 0x65, 0x78, 0x74, 0x0a, 0x0a, 0x2d, 0x2d, 0x58, 0x58, - 0x58, 0x58, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72, 0x79, - 0x20, 0x74, 0x65, 0x78, 0x74, 0x2d, 0x2d, 0xae, 0x65, 0x23, - 0x23, 0x23, 0x23, 0x23, 0x6f, 0x66, 0x6f, 0x6f, 0x20, 0x62, - 0x61, 0x72, 0x20, 0x66, 0x6f, 0x6f, 0x20, 0x66, 0x6f, 0x6f, - 0x64, 0x5f, 0x5f, 0x5f, 0x5f, 0x67, 0x66, 0x6f, 0x6f, 0x20, - 0x62, 0x61, 0x72, 0x66, 0x28, 0x29, 0x28, 0x29, 0x28, 0x29, - 0xd9, 0x03, 0xe8, 0x6b, 0x72, 0x61, 0x62, 0x20, 0x72, 0x61, - 0x62, 0x20, 0x6f, 0x6f, 0x66, 0x16, 0x6f, 0x66, 0x6f, 0x6f, - 0x20, 0x66, 0x6f, 0x6f, 0x20, 0x66, 0x6f, 0x6f, 0x20, 0x66, - 0x6f, 0x6f, 0x62, 0x5e, 0x5e, 0x69, 0x6f, 0x6f, 0x6f, 0x6f, - 0x6f, 0x6f, 0x6f, 0x6f, 0x66, 0x18, 0x63, 0x6d, 0x66, 0x66, - 0x66, 0x66, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, - 0x66, 0x63, 0x52, 0x46, 0x43, 0xd8, 0x20, 0x78, 0x31, 0x68, - 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x74, 0x6f, 0x6f, - 0x6c, 0x73, 0x2e, 0x69, 0x65, 0x74, 0x66, 0x2e, 0x6f, 0x72, - 0x67, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x2f, 0x72, 0x66, 0x63, - 0x37, 0x30, 0x34, 0x39, 0x23, 0x73, 0x65, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x2d, 0x32, 0x2e, 0x34, 0x2e, 0x35, 0x18, 0x89, - 0xd8, 0x20, 0x6f, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, - 0x63, 0x62, 0x6f, 0x72, 0x2e, 0x6d, 0x65, 0x2f, 0x68, 0x77, - 0x68, 0x65, 0x6e, 0x69, 0x6d, 0x36, 0x34, 0xd8, 0x22, 0x6c, - 0x63, 0x47, 0x78, 0x6c, 0x59, 0x58, 0x4e, 0x31, 0x63, 0x6d, - 0x55, 0x75, 0x18, 0x40, 0xd8, 0x22, 0x68, 0x63, 0x33, 0x56, - 0x79, 0x5a, 0x53, 0x34, 0x3d, 0x64, 0x70, 0x6f, 0x70, 0x6f, - 0xd8, 0x23, 0x68, 0x31, 0x30, 0x30, 0x5c, 0x73, 0x2a, 0x6d, - 0x6b, 0x38, 0x32, 0xd8, 0x23, 0x66, 0x70, 0x65, 0x72, 0x6c, - 0x5c, 0x42, 0x63, 0x4e, 0x65, 0x64, 0xd8, 0x24, 0x79, 0x01, - 0x57, 0x4d, 0x49, 0x4d, 0x45, 0x2d, 0x56, 0x65, 0x72, 0x73, - 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x31, 0x2e, 0x30, 0x0a, 0x43, - 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x54, 0x79, 0x70, - 0x65, 0x3a, 0x20, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x61, - 0x72, 0x74, 0x2f, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x3b, 0x0a, - 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x3d, 0x22, - 0x58, 0x58, 0x58, 0x58, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61, - 0x72, 0x79, 0x20, 0x74, 0x65, 0x78, 0x74, 0x22, 0x0a, 0x0a, - 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x61, 0x20, - 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x61, 0x72, 0x74, 0x20, - 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x20, 0x69, 0x6e, - 0x20, 0x4d, 0x49, 0x4d, 0x45, 0x20, 0x66, 0x6f, 0x72, 0x6d, - 0x61, 0x74, 0x2e, 0x0a, 0x0a, 0x2d, 0x2d, 0x58, 0x58, 0x58, - 0x58, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x20, - 0x74, 0x65, 0x78, 0x74, 0x0a, 0x43, 0x6f, 0x6e, 0x74, 0x65, - 0x6e, 0x74, 0x2d, 0x54, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x74, - 0x65, 0x78, 0x74, 0x2f, 0x70, 0x6c, 0x61, 0x69, 0x6e, 0x0a, - 0x0a, 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, - 0x68, 0x65, 0x20, 0x62, 0x6f, 0x64, 0x79, 0x20, 0x74, 0x65, - 0x78, 0x74, 0x0a, 0x0a, 0x2d, 0x2d, 0x58, 0x58, 0x58, 0x58, - 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x20, 0x74, - 0x65, 0x78, 0x74, 0x0a, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, - 0x74, 0x2d, 0x54, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x74, 0x65, - 0x78, 0x74, 0x2f, 0x70, 0x6c, 0x61, 0x69, 0x6e, 0x3b, 0x0a, - 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x44, 0x69, - 0x73, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, - 0x20, 0x61, 0x74, 0x74, 0x61, 0x63, 0x68, 0x6d, 0x65, 0x6e, - 0x74, 0x3b, 0x0a, 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, - 0x65, 0x3d, 0x22, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x74, 0x78, - 0x74, 0x22, 0x0a, 0x0a, 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, - 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, 0x74, 0x74, 0x61, - 0x63, 0x68, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x74, 0x65, 0x78, - 0x74, 0x0a, 0x0a, 0x2d, 0x2d, 0x58, 0x58, 0x58, 0x58, 0x62, - 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x20, 0x74, 0x65, - 0x78, 0x74, 0x2d, 0x2d, 0x0a, 0xd8, 0x24, 0x79, 0x01, 0x57, - 0x4d, 0x49, 0x4d, 0x45, 0x2d, 0x56, 0x65, 0x72, 0x73, 0x69, - 0x6f, 0x6e, 0x3a, 0x20, 0x31, 0x2e, 0x30, 0x0a, 0x43, 0x6f, - 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x54, 0x79, 0x70, 0x65, - 0x3a, 0x20, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x61, 0x72, - 0x74, 0x2f, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x3b, 0x0a, 0x62, - 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x3d, 0x22, 0x58, - 0x58, 0x58, 0x58, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72, - 0x79, 0x20, 0x74, 0x65, 0x78, 0x74, 0x22, 0x0a, 0x0a, 0x54, - 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x61, 0x20, 0x6d, - 0x75, 0x6c, 0x74, 0x69, 0x70, 0x61, 0x72, 0x74, 0x20, 0x6d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x20, 0x69, 0x6e, 0x20, - 0x4d, 0x49, 0x4d, 0x45, 0x20, 0x66, 0x6f, 0x72, 0x6d, 0x61, - 0x74, 0x2e, 0x0a, 0x0a, 0x2d, 0x2d, 0x58, 0x58, 0x58, 0x58, - 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x20, 0x74, - 0x65, 0x78, 0x74, 0x0a, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, - 0x74, 0x2d, 0x54, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x74, 0x65, - 0x78, 0x74, 0x2f, 0x70, 0x6c, 0x61, 0x69, 0x6e, 0x0a, 0x0a, - 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, - 0x65, 0x20, 0x62, 0x6f, 0x64, 0x79, 0x20, 0x74, 0x65, 0x78, - 0x74, 0x0a, 0x0a, 0x2d, 0x2d, 0x58, 0x58, 0x58, 0x58, 0x62, - 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x20, 0x74, 0x65, - 0x78, 0x74, 0x0a, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, - 0x2d, 0x54, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x74, 0x65, 0x78, - 0x74, 0x2f, 0x70, 0x6c, 0x61, 0x69, 0x6e, 0x3b, 0x0a, 0x43, - 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x44, 0x69, 0x73, - 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, - 0x61, 0x74, 0x74, 0x61, 0x63, 0x68, 0x6d, 0x65, 0x6e, 0x74, - 0x3b, 0x0a, 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65, - 0x3d, 0x22, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x74, 0x78, 0x74, - 0x22, 0x0a, 0x0a, 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, - 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, 0x74, 0x74, 0x61, 0x63, - 0x68, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x74, 0x65, 0x78, 0x74, - 0x0a, 0x0a, 0x2d, 0x2d, 0x58, 0x58, 0x58, 0x58, 0x62, 0x6f, - 0x75, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x20, 0x74, 0x65, 0x78, - 0x74, 0x2d, 0x2d, 0xc0, 0x74, 0x32, 0x30, 0x30, 0x33, 0x2d, - 0x31, 0x32, 0x2d, 0x31, 0x33, 0x54, 0x31, 0x38, 0x3a, 0x33, - 0x30, 0x3a, 0x30, 0x32, 0x5a, 0xa2, 0x68, 0x42, 0x65, 0x64, - 0x20, 0x74, 0x69, 0x6d, 0x65, 0xc0, 0x78, 0x1c, 0x32, 0x30, - 0x30, 0x33, 0x2d, 0x31, 0x32, 0x2d, 0x31, 0x33, 0x54, 0x31, - 0x38, 0x3a, 0x33, 0x30, 0x3a, 0x30, 0x32, 0x2e, 0x32, 0x35, - 0x2b, 0x30, 0x31, 0x3a, 0x30, 0x30, 0x18, 0x58, 0xc0, 0x78, - 0x1c, 0x32, 0x30, 0x30, 0x33, 0x2d, 0x31, 0x32, 0x2d, 0x31, - 0x33, 0x54, 0x31, 0x38, 0x3a, 0x33, 0x30, 0x3a, 0x30, 0x32, - 0x2e, 0x32, 0x35, 0x2b, 0x30, 0x31, 0x3a, 0x30, 0x30, 0xf7, - 0xa3, 0x64, 0x64, 0x61, 0x72, 0x65, 0xd8, 0x42, 0xf5, 0x62, - 0x75, 0x75, 0xf4, 0x1a, 0x00, 0x0b, 0x41, 0x62, 0xf6, 0x80, - 0xa3, 0x78, 0x1c, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x20, 0x61, - 0x6e, 0x64, 0x20, 0x74, 0x61, 0x67, 0x67, 0x65, 0x64, 0x20, - 0x65, 0x6d, 0x70, 0x74, 0x79, 0x20, 0x61, 0x72, 0x72, 0x61, - 0x79, 0xd9, 0x04, 0x45, 0x80, 0x65, 0x61, 0x6c, 0x61, 0x62, - 0x6c, 0x80, 0x18, 0x2a, 0x80, 0xa1, 0x68, 0x69, 0x6e, 0x20, - 0x61, 0x20, 0x6d, 0x61, 0x70, 0xa1, 0x19, 0x15, 0xb4, 0xa1, - 0x6e, 0x69, 0x6e, 0x20, 0x61, 0x20, 0x69, 0x6e, 0x20, 0x61, - 0x20, 0x69, 0x6e, 0x20, 0x61, 0xd9, 0x23, 0x7f, 0xa0, 0xa5, - 0x62, 0x73, 0x31, 0xd8, 0x58, 0xf8, 0xff, 0x62, 0x73, 0x32, - 0xe0, 0x62, 0x73, 0x33, 0xd8, 0x58, 0xf8, 0x21, 0x1a, 0x05, - 0x44, 0x8c, 0x06, 0xd8, 0x58, 0xf8, 0xff, 0x18, 0x59, 0xd8, - 0x58, 0xf3, 0xd8, 0x25, 0x50, 0x53, 0x4d, 0x41, 0x52, 0x54, - 0x43, 0x53, 0x4c, 0x54, 0x54, 0x43, 0x46, 0x49, 0x43, 0x41, - 0x32, 0xa2, 0x64, 0x55, 0x55, 0x55, 0x55, 0xd8, 0x25, 0x50, - 0x53, 0x4d, 0x41, 0x52, 0x54, 0x43, 0x53, 0x4c, 0x54, 0x54, - 0x43, 0x46, 0x49, 0x43, 0x41, 0x32, 0x18, 0x63, 0xd8, 0x25, - 0x50, 0x53, 0x4d, 0x41, 0x52, 0x54, 0x43, 0x53, 0x4c, 0x54, - 0x54, 0x43, 0x46, 0x49, 0x43, 0x41, 0x32, 0xf5, 0xf4, 0xa2, - 0x71, 0x47, 0x65, 0x6f, 0x72, 0x67, 0x65, 0x20, 0x69, 0x73, - 0x20, 0x74, 0x68, 0x65, 0x20, 0x6d, 0x61, 0x6e, 0xf5, 0x19, - 0x10, 0x41, 0xf5, 0xC2, 0x49, 0x01, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xC3, 0x49, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xA4, 0x63, 0x42, 0x4E, 0x2B, - 0xC2, 0x49, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x18, 0x40, 0xC2, 0x49, 0x01, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x63, 0x42, 0x4E, 0x2D, 0xC3, 0x49, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, - 0x3F, 0xC3, 0x49, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00 -}; - - -static const char *szMIME = "\ -MIME-Version: 1.0\n\ -Content-Type: multipart/mixed;\n\ -boundary=\"XXXXboundary text\"\n\ -\n\ -This is a multipart message in MIME format.\n\ -\n\ ---XXXXboundary text\n\ -Content-Type: text/plain\n\ -\n\ -this is the body text\n\ -\n\ ---XXXXboundary text\n\ -Content-Type: text/plain;\n\ -Content-Disposition: attachment;\n\ -filename=\"test.txt\"\n\ -\n\ -this is the attachment text\n\ -\n\ ---XXXXboundary text--"; - - -int AllAddMethodsTest() -{ - // TODO: this test should be broken down into several so it is more managable. Tags and labels could be more sensible - QCBOREncodeContext ECtx; - int nReturn = 0; - - QCBOREncode_Init(&ECtx, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf)); - - QCBOREncode_OpenArray(&ECtx); - - // Some ints that are tagged and have strings preceeding them (not labels becase it is not a map) - QCBOREncode_AddSZString(&ECtx, "UINT62"); - QCBOREncode_AddTag(&ECtx, 100); - QCBOREncode_AddUInt64(&ECtx, 89989909); - QCBOREncode_AddSZString(&ECtx, "INT64"); - QCBOREncode_AddTag(&ECtx, 76); - QCBOREncode_AddInt64(&ECtx, 77689989909); - QCBOREncode_AddUInt64(&ECtx,0); - QCBOREncode_AddInt64(&ECtx, -44); - - // ints that go in maps - QCBOREncode_OpenMap(&ECtx); - QCBOREncode_AddUInt64ToMap(&ECtx, "LBL", 77); - QCBOREncode_AddUInt64ToMapN(&ECtx, -4, 88); - QCBOREncode_AddInt64ToMap(&ECtx, "NEGLBLTHAT IS KIND OF LONG", -2394893489238); - QCBOREncode_AddInt64ToMapN(&ECtx, -100000000, -800000000); - QCBOREncode_CloseMap(&ECtx); - - // Epoch Date - QCBOREncode_AddDateEpoch(&ECtx, 2383748234); - - // Epoch date with labels - QCBOREncode_OpenMap(&ECtx); - QCBOREncode_AddDateEpochToMap(&ECtx, "LongLiveDenisRitchie", 1400000000); - QCBOREncode_AddDateEpochToMap(&ECtx, "time()", 1477263730); - QCBOREncode_AddDateEpochToMapN(&ECtx, -1969, 1477263222); - QCBOREncode_CloseMap(&ECtx); - - // Binary blobs - QCBOREncode_AddBytes(&ECtx, ((UsefulBufC) {(uint8_t []){0xff, 0x00}, 2})); - - // binary blobs in maps - QCBOREncode_OpenMap(&ECtx); - QCBOREncode_AddSZString(&ECtx, "binbin"); - QCBOREncode_AddTag(&ECtx, 100000); - QCBOREncode_AddBytes(&ECtx, ((UsefulBufC) {(uint8_t []){0x00}, 1})); - QCBOREncode_AddBytesToMap(&ECtx, "blabel", ((UsefulBufC) {(uint8_t []){0x01, 0x02, 0x03}, 3})); - QCBOREncode_AddBytesToMapN(&ECtx, 0, ((UsefulBufC){(uint8_t []){0x04, 0x02, 0x03, 0xfe}, 4})); - QCBOREncode_CloseMap(&ECtx); - - // text blobs - QCBOREncode_AddText(&ECtx, UsefulBuf_FROM_SZ_LITERAL("bar bar foo bar")); - QCBOREncode_AddSZString(&ECtx, "oof\n"); - QCBOREncode_AddURI(&ECtx, UsefulBuf_FROM_SZ_LITERAL("http://stackoverflow.com/questions/28059697/how-do-i-toggle-between-debug-and-release-builds-in-xcode-6-7-8")); - QCBOREncode_AddB64Text(&ECtx, UsefulBuf_FROM_SZ_LITERAL("YW55IGNhcm5hbCBwbGVhc3VyZQ==")); - QCBOREncode_AddRegex(&ECtx, UsefulBuf_FROM_SZ_LITERAL("[^abc]+")); - QCBOREncode_AddMIMEData(&ECtx, UsefulBuf_FromSZ(szMIME)); - - // text blobs in maps - QCBOREncode_OpenMap(&ECtx); - QCBOREncode_AddTextToMap(&ECtx, "#####", UsefulBuf_FROM_SZ_LITERAL("foo bar foo foo")); - QCBOREncode_AddTextToMap(&ECtx, "____", UsefulBuf_FROM_SZ_LITERAL("foo bar")); - QCBOREncode_AddSZString(&ECtx, "()()()"); - QCBOREncode_AddTag(&ECtx, 1000); - QCBOREncode_AddSZString(&ECtx, "rab rab oof"); - QCBOREncode_AddTextToMapN(&ECtx,22, UsefulBuf_FROM_SZ_LITERAL("foo foo foo foo")); - QCBOREncode_AddSZStringToMap(&ECtx, "^^", "oooooooof"); - QCBOREncode_AddSZStringToMapN(&ECtx, 99, "ffffoooooooof"); - QCBOREncode_AddURIToMap(&ECtx, "RFC", UsefulBuf_FROM_SZ_LITERAL("https://tools.ietf.org/html/rfc7049#section-2.4.5")); - QCBOREncode_AddURIToMapN(&ECtx, 0x89, UsefulBuf_FROM_SZ_LITERAL("http://cbor.me/")); - QCBOREncode_AddB64TextToMap(&ECtx, "whenim64", UsefulBuf_FROM_SZ_LITERAL("cGxlYXN1cmUu")); - QCBOREncode_AddB64TextToMapN(&ECtx, 64, UsefulBuf_FROM_SZ_LITERAL("c3VyZS4=")); - QCBOREncode_AddRegexToMap(&ECtx, "popo", UsefulBuf_FROM_SZ_LITERAL("100\\s*mk")); // x code string literal bug - QCBOREncode_AddRegexToMapN(&ECtx, -51, UsefulBuf_FROM_SZ_LITERAL("perl\\B")); // x code string literal bug - QCBOREncode_AddMIMEDataToMap(&ECtx, "Ned", UsefulBuf_FromSZ(szMIME)); - QCBOREncode_AddMIMEDataToMapN(&ECtx, 10, UsefulBuf_FromSZ(szMIME)); - QCBOREncode_CloseMap(&ECtx); - - // Date strings - QCBOREncode_AddDateString(&ECtx, "2003-12-13T18:30:02Z"); - QCBOREncode_OpenMap(&ECtx); - QCBOREncode_AddDateStringToMap(&ECtx, "Bed time", "2003-12-13T18:30:02.25+01:00"); - QCBOREncode_AddDateStringToMapN(&ECtx, 88, "2003-12-13T18:30:02.25+01:00"); - QCBOREncode_CloseMap(&ECtx); - - // true / false ... - QCBOREncode_AddSimple(&ECtx, CBOR_SIMPLEV_UNDEF); - QCBOREncode_OpenMap(&ECtx); - QCBOREncode_AddSZString(&ECtx, "dare"); - QCBOREncode_AddTag(&ECtx, 66); - QCBOREncode_AddBool(&ECtx, true); - QCBOREncode_AddBoolToMap(&ECtx, "uu", false); - QCBOREncode_AddSimpleToMapN(&ECtx, 737634, CBOR_SIMPLEV_NULL); - QCBOREncode_CloseMap(&ECtx); - - // opening an array - QCBOREncode_OpenArray(&ECtx); - QCBOREncode_CloseArray(&ECtx); - - // opening arrays in a map - QCBOREncode_OpenMap(&ECtx); - QCBOREncode_AddSZString(&ECtx, "label and tagged empty array"); - QCBOREncode_AddTag(&ECtx, 1093); - QCBOREncode_OpenArray(&ECtx); - QCBOREncode_CloseArray(&ECtx); - QCBOREncode_OpenArrayInMap(&ECtx, "alabl"); - QCBOREncode_CloseArray(&ECtx); - QCBOREncode_OpenArrayInMapN(&ECtx, 42); - QCBOREncode_CloseArray(&ECtx); - QCBOREncode_CloseMap(&ECtx); - - // opening maps with labels and tagging - QCBOREncode_OpenMap(&ECtx); - QCBOREncode_OpenMapInMap(&ECtx, "in a map"); - QCBOREncode_OpenMapInMapN(&ECtx, 5556); - QCBOREncode_AddSZString(&ECtx, "in a in a in a"); - QCBOREncode_AddTag(&ECtx, 9087); - QCBOREncode_OpenMap(&ECtx); - QCBOREncode_CloseMap(&ECtx); - QCBOREncode_CloseMap(&ECtx); - QCBOREncode_CloseMap(&ECtx); - QCBOREncode_CloseMap(&ECtx); - - - // Extended simple values (these are not standard...) - QCBOREncode_OpenMap(&ECtx); - QCBOREncode_AddSZString(&ECtx, "s1"); - QCBOREncode_AddTag(&ECtx, 88); - QCBOREncode_AddSimple(&ECtx, 255); - QCBOREncode_AddSimpleToMap(&ECtx, "s2", 0); - QCBOREncode_AddSZString(&ECtx, "s3"); - QCBOREncode_AddTag(&ECtx, 88); - QCBOREncode_AddSimple(&ECtx, 33); - QCBOREncode_AddInt64(&ECtx, 88378374); // label before tag - QCBOREncode_AddTag(&ECtx, 88); - QCBOREncode_AddSimple(&ECtx, 255); - QCBOREncode_AddInt64(&ECtx, 89); // label before tag - QCBOREncode_AddTag(&ECtx, 88); - QCBOREncode_AddSimple(&ECtx, 19); - QCBOREncode_CloseMap(&ECtx); - - // UUIDs - static const uint8_t ppppUUID[] = {0x53, 0x4D, 0x41, 0x52, 0x54, 0x43, 0x53, 0x4C, 0x54, 0x54, 0x43, 0x46, 0x49, 0x43, 0x41, 0x32}; - const UsefulBufC XXUUID = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(ppppUUID); - QCBOREncode_AddBinaryUUID(&ECtx, XXUUID); - QCBOREncode_OpenMap(&ECtx); - QCBOREncode_AddBinaryUUIDToMap(&ECtx, "UUUU", XXUUID); - QCBOREncode_AddBinaryUUIDToMapN(&ECtx, 99, XXUUID); - QCBOREncode_CloseMap(&ECtx); - - // Bool - QCBOREncode_AddBool(&ECtx, true); - QCBOREncode_AddBool(&ECtx, false); - QCBOREncode_OpenMap(&ECtx); - QCBOREncode_AddBoolToMap(&ECtx, "George is the man", true); - QCBOREncode_AddBoolToMapN(&ECtx, 010101, true); - QCBOREncode_CloseMap(&ECtx); - - - static const uint8_t pBignum[] = {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - const UsefulBufC BIGNUM = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pBignum); - QCBOREncode_AddPositiveBignum(&ECtx, BIGNUM); - QCBOREncode_AddNegativeBignum(&ECtx, BIGNUM); - QCBOREncode_OpenMap(&ECtx); - QCBOREncode_AddPositiveBignumToMap(&ECtx, "BN+", BIGNUM); - QCBOREncode_AddPositiveBignumToMapN(&ECtx, 64, BIGNUM); - QCBOREncode_AddNegativeBignumToMap(&ECtx, "BN-", BIGNUM); - QCBOREncode_AddNegativeBignumToMapN(&ECtx, -64, BIGNUM); - QCBOREncode_CloseMap(&ECtx); - - QCBOREncode_CloseArray(&ECtx); - - UsefulBufC Enc; - - if(QCBOREncode_Finish(&ECtx, &Enc)) { - nReturn = -1; - goto Done; - } - - if(CheckResults(Enc, spExpectedEncodedAll)) - nReturn = -2; - -Done: - return nReturn; -} - -/* - 98 2F # array(47) - 3B 7FFFFFFFFFFFFFFF # negative(9223372036854775807) - 3B 0000000100000000 # negative(4294967296) - 3A FFFFFFFF # negative(4294967295) - 3A FFFFFFFE # negative(4294967294) - 3A FFFFFFFD # negative(4294967293) - 3A 7FFFFFFF # negative(2147483647) - 3A 7FFFFFFE # negative(2147483646) - 3A 00010001 # negative(65537) - 3A 00010000 # negative(65536) - 39 FFFF # negative(65535) - 39 FFFE # negative(65534) - 39 FFFD # negative(65533) - 39 0100 # negative(256) - 38 FF # negative(255) - 38 FE # negative(254) - 38 FD # negative(253) - 38 18 # negative(24) - 37 # negative(23) - 36 # negative(22) - 20 # negative(0) - 00 # unsigned(0) - 00 # unsigned(0) - 01 # unsigned(1) - 16 # unsigned(22) - 17 # unsigned(23) - 18 18 # unsigned(24) - 18 19 # unsigned(25) - 18 1A # unsigned(26) - 18 FE # unsigned(254) - 18 FF # unsigned(255) - 19 0100 # unsigned(256) - 19 0101 # unsigned(257) - 19 FFFE # unsigned(65534) - 19 FFFF # unsigned(65535) - 1A 00010000 # unsigned(65536) - 1A 00010001 # unsigned(65537) - 1A 00010002 # unsigned(65538) - 1A 7FFFFFFF # unsigned(2147483647) - 1A 7FFFFFFF # unsigned(2147483647) - 1A 80000000 # unsigned(2147483648) - 1A 80000001 # unsigned(2147483649) - 1A FFFFFFFE # unsigned(4294967294) - 1A FFFFFFFF # unsigned(4294967295) - 1B 0000000100000000 # unsigned(4294967296) - 1B 0000000100000001 # unsigned(4294967297) - 1B 7FFFFFFFFFFFFFFF # unsigned(9223372036854775807) - 1B FFFFFFFFFFFFFFFF # unsigned(18446744073709551615) - */ -static const uint8_t spExpectedEncodedInts[] = { - 0x98, 0x2f, 0x3b, 0x7f, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x3b, 0x00, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x00, 0x3a, 0xff, 0xff, 0xff, - 0xff, 0x3a, 0xff, 0xff, 0xff, 0xfe, 0x3a, 0xff, - 0xff, 0xff, 0xfd, 0x3a, 0x7f, 0xff, 0xff, 0xff, - 0x3a, 0x7f, 0xff, 0xff, 0xfe, 0x3a, 0x00, 0x01, - 0x00, 0x01, 0x3a, 0x00, 0x01, 0x00, 0x00, 0x39, - 0xff, 0xff, 0x39, 0xff, 0xfe, 0x39, 0xff, 0xfd, - 0x39, 0x01, 0x00, 0x38, 0xff, 0x38, 0xfe, 0x38, - 0xfd, 0x38, 0x18, 0x37, 0x36, 0x20, 0x00, 0x00, - 0x01, 0x16, 0x17, 0x18, 0x18, 0x18, 0x19, 0x18, - 0x1a, 0x18, 0xfe, 0x18, 0xff, 0x19, 0x01, 0x00, - 0x19, 0x01, 0x01, 0x19, 0xff, 0xfe, 0x19, 0xff, - 0xff, 0x1a, 0x00, 0x01, 0x00, 0x00, 0x1a, 0x00, - 0x01, 0x00, 0x01, 0x1a, 0x00, 0x01, 0x00, 0x02, - 0x1a, 0x7f, 0xff, 0xff, 0xff, 0x1a, 0x7f, 0xff, - 0xff, 0xff, 0x1a, 0x80, 0x00, 0x00, 0x00, 0x1a, - 0x80, 0x00, 0x00, 0x01, 0x1a, 0xff, 0xff, 0xff, - 0xfe, 0x1a, 0xff, 0xff, 0xff, 0xff, 0x1b, 0x00, - 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x1b, - 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, - 0x1b, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x1b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff}; - -/* - - Test the generation of integers. This also ends up testing - encoding of all the different lengths. It encodes integers - of many lengths and values, especially around the boundaries - for different types of integers. It compares the output - to expected values generated from http://cbor.me. - - */ -int IntegerValuesTest1() -{ - QCBOREncodeContext ECtx; - int nReturn = 0; - - QCBOREncode_Init(&ECtx, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf)); - QCBOREncode_OpenArray(&ECtx); - - QCBOREncode_AddInt64(&ECtx, -9223372036854775807LL - 1); - QCBOREncode_AddInt64(&ECtx, -4294967297); - QCBOREncode_AddInt64(&ECtx, -4294967296); - QCBOREncode_AddInt64(&ECtx, -4294967295); - QCBOREncode_AddInt64(&ECtx, -4294967294); - QCBOREncode_AddInt64(&ECtx, -2147483648); - QCBOREncode_AddInt64(&ECtx, -2147483647); - QCBOREncode_AddInt64(&ECtx, -65538); - QCBOREncode_AddInt64(&ECtx, -65537); - QCBOREncode_AddInt64(&ECtx, -65536); - QCBOREncode_AddInt64(&ECtx, -65535); - QCBOREncode_AddInt64(&ECtx, -65534); - QCBOREncode_AddInt64(&ECtx, -257); - QCBOREncode_AddInt64(&ECtx, -256); - QCBOREncode_AddInt64(&ECtx, -255); - QCBOREncode_AddInt64(&ECtx, -254); - QCBOREncode_AddInt64(&ECtx, -25); - QCBOREncode_AddInt64(&ECtx, -24); - QCBOREncode_AddInt64(&ECtx, -23); - QCBOREncode_AddInt64(&ECtx, -1); - QCBOREncode_AddInt64(&ECtx, 0); - QCBOREncode_AddUInt64(&ECtx, 0ULL); - QCBOREncode_AddInt64(&ECtx, 1); - QCBOREncode_AddInt64(&ECtx, 22); - QCBOREncode_AddInt64(&ECtx, 23); - QCBOREncode_AddInt64(&ECtx, 24); - QCBOREncode_AddInt64(&ECtx, 25); - QCBOREncode_AddInt64(&ECtx, 26); - QCBOREncode_AddInt64(&ECtx, 254); - QCBOREncode_AddInt64(&ECtx, 255); - QCBOREncode_AddInt64(&ECtx, 256); - QCBOREncode_AddInt64(&ECtx, 257); - QCBOREncode_AddInt64(&ECtx, 65534); - QCBOREncode_AddInt64(&ECtx, 65535); - QCBOREncode_AddInt64(&ECtx, 65536); - QCBOREncode_AddInt64(&ECtx, 65537); - QCBOREncode_AddInt64(&ECtx, 65538); - QCBOREncode_AddInt64(&ECtx, 2147483647); - QCBOREncode_AddInt64(&ECtx, 2147483647); - QCBOREncode_AddInt64(&ECtx, 2147483648); - QCBOREncode_AddInt64(&ECtx, 2147483649); - QCBOREncode_AddInt64(&ECtx, 4294967294); - QCBOREncode_AddInt64(&ECtx, 4294967295); - QCBOREncode_AddInt64(&ECtx, 4294967296); - QCBOREncode_AddInt64(&ECtx, 4294967297); - QCBOREncode_AddInt64(&ECtx, 9223372036854775807LL); - QCBOREncode_AddUInt64(&ECtx, 18446744073709551615ULL); - - QCBOREncode_CloseArray(&ECtx); - - UsefulBufC Enc; - if(QCBOREncode_Finish(&ECtx, &Enc)) { - nReturn = -1; - } - - if(CheckResults(Enc, spExpectedEncodedInts)) - return -2; - - return(nReturn); -} - - -/* - 85 # array(5) - F5 # primitive(21) - F4 # primitive(20) - F6 # primitive(22) - F7 # primitive(23) - A1 # map(1) - 65 # text(5) - 554E446566 # "UNDef" - F7 # primitive(23) - */ -static const uint8_t spExpectedEncodedSimple[] = { - 0x85, 0xf5, 0xf4, 0xf6, 0xf7, 0xa1, 0x65, 0x55, 0x4e, 0x44, 0x65, 0x66, 0xf7}; - -int SimpleValuesTest1() -{ - QCBOREncodeContext ECtx; - int nReturn = 0; - - QCBOREncode_Init(&ECtx, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf)); - QCBOREncode_OpenArray(&ECtx); - - QCBOREncode_AddSimple(&ECtx, CBOR_SIMPLEV_TRUE); - QCBOREncode_AddSimple(&ECtx, CBOR_SIMPLEV_FALSE); - QCBOREncode_AddSimple(&ECtx, CBOR_SIMPLEV_NULL); - QCBOREncode_AddSimple(&ECtx, CBOR_SIMPLEV_UNDEF); - - QCBOREncode_OpenMap(&ECtx); - - QCBOREncode_AddSimpleToMap(&ECtx, "UNDef", CBOR_SIMPLEV_UNDEF); - QCBOREncode_CloseMap(&ECtx); - - QCBOREncode_CloseArray(&ECtx); - - UsefulBufC ECBOR; - if(QCBOREncode_Finish(&ECtx, &ECBOR)) { - nReturn = -1; - } - - if(CheckResults(ECBOR, spExpectedEncodedSimple)) - return -2; - - return(nReturn); -} - - -/* - 83 # array(3) - C0 # tag(0) - 74 # text(20) - 323031332D30332D32315432303A30343A30305A # "2013-03-21T20:04:00Z" - C1 # tag(1) - 1A 514B67B0 # unsigned(1363896240) - A2 # map(2) - 78 19 # text(25) - 53616D706C6520446174652066726F6D205246432033333339 # "Sample Date from RFC 3339" - C0 # tag(0) - 77 # text(23) - 313938352D30342D31325432333A32303A35302E35325A # "1985-04-12T23:20:50.52Z" - 62 # text(2) - 5344 # "SD" - C1 # tag(1) - 19 03E7 # unsigned(999) - */ -static const uint8_t spExpectedEncodedDates[] = { - 0x83, 0xc0, 0x74, 0x32, 0x30, 0x31, 0x33, 0x2d, 0x30, 0x33, - 0x2d, 0x32, 0x31, 0x54, 0x32, 0x30, 0x3a, 0x30, 0x34, 0x3a, - 0x30, 0x30, 0x5a, 0xc1, 0x1a, 0x51, 0x4b, 0x67, 0xb0, 0xa2, - 0x78, 0x19, 0x53, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x20, 0x44, - 0x61, 0x74, 0x65, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x52, - 0x46, 0x43, 0x20, 0x33, 0x33, 0x33, 0x39, 0xc0, 0x77, 0x31, - 0x39, 0x38, 0x35, 0x2d, 0x30, 0x34, 0x2d, 0x31, 0x32, 0x54, - 0x32, 0x33, 0x3a, 0x32, 0x30, 0x3a, 0x35, 0x30, 0x2e, 0x35, - 0x32, 0x5a, 0x62, 0x53, 0x44, 0xc1, 0x19, 0x03, 0xe7 -}; - -int EncodeDateTest() -{ - QCBOREncodeContext ECtx; - int nReturn = 0; - - QCBOREncode_Init(&ECtx, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf)); - - QCBOREncode_OpenArray(&ECtx); - - - QCBOREncode_AddDateString(&ECtx, "2013-03-21T20:04:00Z"); // from CBOR RFC - QCBOREncode_AddDateEpoch(&ECtx, 1363896240); // from CBOR RFC - - - QCBOREncode_OpenMap(&ECtx); - - QCBOREncode_AddDateStringToMap(&ECtx, "Sample Date from RFC 3339", "1985-04-12T23:20:50.52Z"); - - QCBOREncode_AddDateEpochToMap(&ECtx, "SD", 999); - - QCBOREncode_CloseMap(&ECtx); - - QCBOREncode_CloseArray(&ECtx); - - UsefulBufC ECBOR; - - if(QCBOREncode_Finish(&ECtx, &ECBOR)) { - nReturn = -1; - } - - if(CheckResults(ECBOR, spExpectedEncodedDates)) - return -2; - - return(nReturn); -} - - -int ArrayNestingTest1() -{ - QCBOREncodeContext ECtx; - int i; - int nReturn = 0; - - QCBOREncode_Init(&ECtx, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf)); - for(i = QCBOR_MAX_ARRAY_NESTING; i; i--) { - QCBOREncode_OpenArray(&ECtx); - } - for(i = QCBOR_MAX_ARRAY_NESTING; i; i--) { - QCBOREncode_CloseArray(&ECtx); - } - UsefulBufC Encoded; - if(QCBOREncode_Finish(&ECtx, &Encoded)) { - nReturn = -1; - } - - return(nReturn); -} - - - -int ArrayNestingTest2() -{ - QCBOREncodeContext ECtx; - int i; - int nReturn = 0; - - QCBOREncode_Init(&ECtx, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf)); - for(i = QCBOR_MAX_ARRAY_NESTING+1; i; i--) { - QCBOREncode_OpenArray(&ECtx); - } - for(i = QCBOR_MAX_ARRAY_NESTING; i; i--) { - QCBOREncode_CloseArray(&ECtx); - } - - UsefulBufC Encoded; - if(QCBOREncode_Finish(&ECtx, &Encoded) != QCBOR_ERR_ARRAY_NESTING_TOO_DEEP) { - nReturn = -1; - } - - return(nReturn); -} - - - -int ArrayNestingTest3() -{ - QCBOREncodeContext ECtx; - int i; - int nReturn = 0; - - QCBOREncode_Init(&ECtx, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf)); - for(i = QCBOR_MAX_ARRAY_NESTING; i; i--) { - QCBOREncode_OpenArray(&ECtx); - } - for(i = QCBOR_MAX_ARRAY_NESTING+1 ; i; i--) { - QCBOREncode_CloseArray(&ECtx); - } - UsefulBufC Encoded; - if(QCBOREncode_Finish(&ECtx, &Encoded) != QCBOR_ERR_TOO_MANY_CLOSES) { - nReturn = -1; - } - - return(nReturn); -} - - -/* - 81 # array(1) - 81 # array(1) - 81 # array(1) - 81 # array(1) - 80 # array(0) -*/ -static const uint8_t spFiveArrarys[] = {0x81, 0x81, 0x81, 0x81, 0x80}; - -// Validated at http://cbor.me and by manually examining its output -/* - 82 # array(2) - 81 # array(1) - 81 # array(1) - 81 # array(1) - 81 # array(1) - 80 # array(0) - 98 2F # array(47) - 3B 7FFFFFFFFFFFFFFF # negative(9223372036854775807) - 3B 0000000100000000 # negative(4294967296) - 3A FFFFFFFF # negative(4294967295) - 3A FFFFFFFE # negative(4294967294) - 3A FFFFFFFD # negative(4294967293) - 3A 7FFFFFFF # negative(2147483647) - 3A 7FFFFFFE # negative(2147483646) - 3A 00010001 # negative(65537) - 3A 00010000 # negative(65536) - 39 FFFF # negative(65535) - 39 FFFE # negative(65534) - 39 FFFD # negative(65533) - 39 0100 # negative(256) - 38 FF # negative(255) - 38 FE # negative(254) - 38 FD # negative(253) - 38 18 # negative(24) - 37 # negative(23) - 36 # negative(22) - 20 # negative(0) - 00 # unsigned(0) - 00 # unsigned(0) - 01 # unsigned(1) - 16 # unsigned(22) - 17 # unsigned(23) - 18 18 # unsigned(24) - 18 19 # unsigned(25) - 18 1A # unsigned(26) - 18 FE # unsigned(254) - 18 FF # unsigned(255) - 19 0100 # unsigned(256) - 19 0101 # unsigned(257) - 19 FFFE # unsigned(65534) - 19 FFFF # unsigned(65535) - 1A 00010000 # unsigned(65536) - 1A 00010001 # unsigned(65537) - 1A 00010002 # unsigned(65538) - 1A 7FFFFFFF # unsigned(2147483647) - 1A 7FFFFFFF # unsigned(2147483647) - 1A 80000000 # unsigned(2147483648) - 1A 80000001 # unsigned(2147483649) - 1A FFFFFFFE # unsigned(4294967294) - 1A FFFFFFFF # unsigned(4294967295) - 1B 0000000100000000 # unsigned(4294967296) - 1B 0000000100000001 # unsigned(4294967297) - 1B 7FFFFFFFFFFFFFFF # unsigned(9223372036854775807) - 1B FFFFFFFFFFFFFFFF # unsigned(18446744073709551615) - */ -static const uint8_t spEncodeRawExpected[] = { - 0x82, 0x81, 0x81, 0x81, 0x81, 0x80, 0x98, 0x2f, - 0x3b, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x3b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, - 0x00, 0x00, 0x3a, 0xff, 0xff, 0xff, 0xff, 0x3a, - 0xff, 0xff, 0xff, 0xfe, 0x3a, 0xff, 0xff, 0xff, - 0xfd, 0x3a, 0x7f, 0xff, 0xff, 0xff, 0x3a, 0x7f, - 0xff, 0xff, 0xfe, 0x3a, 0x00, 0x01, 0x00, 0x01, - 0x3a, 0x00, 0x01, 0x00, 0x00, 0x39, 0xff, 0xff, - 0x39, 0xff, 0xfe, 0x39, 0xff, 0xfd, 0x39, 0x01, - 0x00, 0x38, 0xff, 0x38, 0xfe, 0x38, 0xfd, 0x38, - 0x18, 0x37, 0x36, 0x20, 0x00, 0x00, 0x01, 0x16, - 0x17, 0x18, 0x18, 0x18, 0x19, 0x18, 0x1a, 0x18, - 0xfe, 0x18, 0xff, 0x19, 0x01, 0x00, 0x19, 0x01, - 0x01, 0x19, 0xff, 0xfe, 0x19, 0xff, 0xff, 0x1a, - 0x00, 0x01, 0x00, 0x00, 0x1a, 0x00, 0x01, 0x00, - 0x01, 0x1a, 0x00, 0x01, 0x00, 0x02, 0x1a, 0x7f, - 0xff, 0xff, 0xff, 0x1a, 0x7f, 0xff, 0xff, 0xff, - 0x1a, 0x80, 0x00, 0x00, 0x00, 0x1a, 0x80, 0x00, - 0x00, 0x01, 0x1a, 0xff, 0xff, 0xff, 0xfe, 0x1a, - 0xff, 0xff, 0xff, 0xff, 0x1b, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, - 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x1b, 0x7f, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1b, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; - - -int EncodeRawTest() -{ - QCBOREncodeContext ECtx; - - QCBOREncode_Init(&ECtx, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf)); - QCBOREncode_OpenArray(&ECtx); - QCBOREncode_AddEncoded(&ECtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spFiveArrarys)); - QCBOREncode_AddEncoded(&ECtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedEncodedInts)); - QCBOREncode_CloseArray(&ECtx); - - UsefulBufC EncodedRawTest; - - if(QCBOREncode_Finish(&ECtx, &EncodedRawTest)) { - return -4; - } - - if(CheckResults(EncodedRawTest, spEncodeRawExpected)) { - return -5; - } - - return 0; -} - -/* - This returns a pointer to spBigBuf - */ -static int CreateMap(uint8_t **pEncoded, size_t *pEncodedLen) -{ - QCBOREncodeContext ECtx; - int nReturn = -1; - - *pEncoded = NULL; - *pEncodedLen = INT32_MAX; - size_t uFirstSizeEstimate = 0; - - // loop runs CBOR encoding twice. First with no buffer to - // calucate the length so buffer can be allocated correctly, - // and last with the buffer to do the actual encoding - do { - QCBOREncode_Init(&ECtx, (UsefulBuf){*pEncoded, *pEncodedLen}); - QCBOREncode_OpenMap(&ECtx); - QCBOREncode_AddInt64ToMap(&ECtx, "first integer", 42); - QCBOREncode_OpenArrayInMap(&ECtx, "an array of two strings"); - QCBOREncode_AddText(&ECtx, ((UsefulBufC) {"string1", 7})); - QCBOREncode_AddText(&ECtx, ((UsefulBufC) {"string2", 7})); - QCBOREncode_CloseArray(&ECtx); - QCBOREncode_OpenMapInMap(&ECtx, "map in a map"); - QCBOREncode_AddBytesToMap(&ECtx,"bytes 1", ((UsefulBufC) { "xxxx", 4})); - QCBOREncode_AddBytesToMap(&ECtx, "bytes 2",((UsefulBufC) { "yyyy", 4})); - QCBOREncode_AddInt64ToMap(&ECtx, "another int", 98); - QCBOREncode_AddTextToMap(&ECtx, "text 2", ((UsefulBufC) {"lies, damn lies and statistics", 30})); - QCBOREncode_CloseMap(&ECtx); - QCBOREncode_CloseMap(&ECtx); - - if(QCBOREncode_FinishGetSize(&ECtx, pEncodedLen)) - goto Done; - if(*pEncoded != NULL) { - if(uFirstSizeEstimate != *pEncodedLen) { - nReturn = 1; - } else { - nReturn = 0; - } - goto Done; - } - *pEncoded = spBigBuf; - uFirstSizeEstimate = *pEncodedLen; - - } while(1); - - Done: - return(nReturn); -} - -/* - A3 # map(3) - 6D # text(13) - 666972737420696E7465676572 # "first integer" - 18 2A # unsigned(42) - 77 # text(23) - 616E206172726179206F662074776F20737472696E6773 # "an array of two strings" - 82 # array(2) - 67 # text(7) - 737472696E6731 # "string1" - 67 # text(7) - 737472696E6732 # "string2" - 6C # text(12) - 6D617020696E2061206D6170 # "map in a map" - A4 # map(4) - 67 # text(7) - 62797465732031 # "bytes 1" - 44 # bytes(4) - 78787878 # "xxxx" - 67 # text(7) - 62797465732032 # "bytes 2" - 44 # bytes(4) - 79797979 # "yyyy" - 6B # text(11) - 616E6F7468657220696E74 # "another int" - 18 62 # unsigned(98) - 66 # text(6) - 746578742032 # "text 2" - 78 1E # text(30) - 6C6965732C2064616D6E206C69657320616E642073746174697374696373 # "lies, damn lies and statistics" - */ -static const uint8_t spValidMapEncoded[] = { - 0xa3, 0x6d, 0x66, 0x69, 0x72, 0x73, 0x74, 0x20, 0x69, 0x6e, - 0x74, 0x65, 0x67, 0x65, 0x72, 0x18, 0x2a, 0x77, 0x61, 0x6e, - 0x20, 0x61, 0x72, 0x72, 0x61, 0x79, 0x20, 0x6f, 0x66, 0x20, - 0x74, 0x77, 0x6f, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, - 0x73, 0x82, 0x67, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x31, - 0x67, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x32, 0x6c, 0x6d, - 0x61, 0x70, 0x20, 0x69, 0x6e, 0x20, 0x61, 0x20, 0x6d, 0x61, - 0x70, 0xa4, 0x67, 0x62, 0x79, 0x74, 0x65, 0x73, 0x20, 0x31, - 0x44, 0x78, 0x78, 0x78, 0x78, 0x67, 0x62, 0x79, 0x74, 0x65, - 0x73, 0x20, 0x32, 0x44, 0x79, 0x79, 0x79, 0x79, 0x6b, 0x61, - 0x6e, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x20, 0x69, 0x6e, 0x74, - 0x18, 0x62, 0x66, 0x74, 0x65, 0x78, 0x74, 0x20, 0x32, 0x78, - 0x1e, 0x6c, 0x69, 0x65, 0x73, 0x2c, 0x20, 0x64, 0x61, 0x6d, - 0x6e, 0x20, 0x6c, 0x69, 0x65, 0x73, 0x20, 0x61, 0x6e, 0x64, - 0x20, 0x73, 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, - 0x73 } ; - - -int MapEncodeTest() -{ - uint8_t *pEncodedMaps; - size_t nEncodedMapLen; - - if(CreateMap(&pEncodedMaps, &nEncodedMapLen)) { - return -1; - } - - int nReturn = 0; - if(memcmp(spValidMapEncoded, pEncodedMaps, sizeof(spValidMapEncoded))) - nReturn = 2; - - return(nReturn); -} - - -/* - @brief Encode the RTIC results - - @param[in] nRResult CBOR_SIMPLEV_TRUE, CBOR_SIMPLEV_FALSE or CBOR_SIMPLEV_NULL - @param[in] time Time stamp in UNIX epoch time or 0 for no time stamp - @param[in] szAlexString Diagnostic code. - @param[in[ pOut Buffer to put the result in - @param[in/out] pnLen Size of pOut buffer when called; length of data output in buffer on return - - @return - One of the CBOR encoder errors. QCBOR_SUCCESS, which is has value 0, if no error. - - The size of pOut should be 30 bytes plus the length of pnLen. If you make it too - short an error will be returned. This function will never write off the end - of the buffer passed to it. - - If the result is 0, then the correct encoded CBOR is in pOut and *pnLen is the - length of the encoded CBOR. - - */ - -static UsefulBufC FormatRTICResults(int nRResult, uint64_t time, const char *szType, const char *szAlexString, UsefulBuf Storage) -{ - // Buffer that the result will be written in to - // It is fixed size and small that a stack variable will be fine - // QCBOREncode will never write off the end of this buffer. If it won't fit QCBOREncode_Finish will return an error. - - // Context for the encoder - QCBOREncodeContext ECtx; - QCBOREncode_Init(&ECtx, Storage); - - // All the RTIC results are grouped in a CBOR Map which will get turned into a JSON Object - // Contents are label / value pairs - QCBOREncode_OpenMap(&ECtx); - - { // Brace / indention just to show CBOR encoding nesting - - // The result: 0 if scan happened and found nothing; 1 if it happened and found something wrong; 2 if it didn't happen - QCBOREncode_AddSimpleToMap(&ECtx, "integrity", nRResult); - - // Add the diagnostic code - QCBOREncode_AddSZStringToMap(&ECtx, "type", szType); - - // Add a time stamp - if(time) { - QCBOREncode_AddDateEpochToMap(&ECtx, "time", time); - } - - // Add the diagnostic code - QCBOREncode_AddSZStringToMap(&ECtx, "diag", szAlexString); - - // Open a subordinate map for telemtry data - QCBOREncode_OpenMapInMap(&ECtx, "telemetry"); - - { // Brace / indention just to show CBOR encoding nesting - - // Add a few fake integers and buffers for now. - QCBOREncode_AddInt64ToMap(&ECtx, "Shoe Size", 12); - - // Add a few fake integers and buffers for now. - QCBOREncode_AddInt64ToMap(&ECtx, "IQ", 0xffffffff); - - // Add a few fake integers and buffers for now. - static const uint8_t pPV[] = {0x66, 0x67, 0x00, 0x56, 0xaa, 0xbb, 0x01, 0x01}; - const UsefulBufC WSPV = {pPV, sizeof(pPV)}; - - QCBOREncode_AddBytesToMap(&ECtx, "WhaleSharkPatternVector", WSPV); - } - } - - // Close the telemetry map - QCBOREncode_CloseMap(&ECtx); - - // Close the map - QCBOREncode_CloseMap(&ECtx); - - UsefulBufC Result; - - QCBOREncode_Finish(&ECtx, &Result); - - return Result; -} - - -/* - A5 # map(5) - 69 # text(9) - 696E74656772697479 # "integrity" - F4 # primitive(20) - 64 # text(4) - 74797065 # "type" - 66 # text(6) - 726563656E74 # "recent" - 64 # text(4) - 74696D65 # "time" - C1 # tag(1) - 1A 580D4172 # unsigned(1477263730) - 64 # text(4) - 64696167 # "diag" - 6A # text(10) - 30784131654335303031 # "0xA1eC5001" - 69 # text(9) - 74656C656D65747279 # "telemetry" - A3 # map(3) - 69 # text(9) - 53686F652053697A65 # "Shoe Size" - 0C # unsigned(12) - 62 # text(2) - 4951 # "IQ" - 1A FFFFFFFF # unsigned(4294967295) - 77 # text(23) - 5768616C65536861726B5061747465726E566563746F72 # "WhaleSharkPatternVector" - 48 # bytes(8) - 66670056AABB0101 # "fg\x00V\xAA\xBB\x01\x01" - */ -static const uint8_t spExpectedRTIC[] = { - 0xa5, 0x69, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x69, 0x74, - 0x79, 0xf4, 0x64, 0x74, 0x79, 0x70, 0x65, 0x66, 0x72, 0x65, - 0x63, 0x65, 0x6e, 0x74, 0x64, 0x74, 0x69, 0x6d, 0x65, 0xc1, - 0x1a, 0x58, 0x0d, 0x41, 0x72, 0x64, 0x64, 0x69, 0x61, 0x67, - 0x6a, 0x30, 0x78, 0x41, 0x31, 0x65, 0x43, 0x35, 0x30, 0x30, - 0x31, 0x69, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, - 0x79, 0xa3, 0x69, 0x53, 0x68, 0x6f, 0x65, 0x20, 0x53, 0x69, - 0x7a, 0x65, 0x0c, 0x62, 0x49, 0x51, 0x1a, 0xff, 0xff, 0xff, - 0xff, 0x77, 0x57, 0x68, 0x61, 0x6c, 0x65, 0x53, 0x68, 0x61, - 0x72, 0x6b, 0x50, 0x61, 0x74, 0x74, 0x65, 0x72, 0x6e, 0x56, - 0x65, 0x63, 0x74, 0x6f, 0x72, 0x48, 0x66, 0x67, 0x00, 0x56, - 0xaa, 0xbb, 0x01, 0x01}; - - -int RTICResultsTest() -{ - const UsefulBufC Encoded = FormatRTICResults(CBOR_SIMPLEV_FALSE, 1477263730, - "recent", "0xA1eC5001", - UsefulBuf_FROM_BYTE_ARRAY(spBigBuf)); - if(UsefulBuf_IsNULLC(Encoded)) { - return -1; - } - - if(CheckResults(Encoded, spExpectedRTIC)) { - return -2; - } - - return 0; -} - - -/* - 82 # array(2) - 19 01C3 # unsigned(451) - 43 # bytes(3) - 1901D2 # "\x19\x01\xD2" -*/ -static const uint8_t spExpectedBstrWrap[] = {0x82, 0x19, 0x01, 0xC3, 0x43, 0x19, 0x01, 0xD2}; - -/* - Very basic bstr wrapping test - */ -int BstrWrapTest() -{ - QCBOREncodeContext EC; - - QCBOREncode_Init(&EC, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf)); - - QCBOREncode_OpenArray(&EC); - QCBOREncode_AddUInt64(&EC, 451); - - QCBOREncode_BstrWrap(&EC); - QCBOREncode_AddUInt64(&EC, 466); - - UsefulBufC Wrapped; - QCBOREncode_CloseBstrWrap(&EC, &Wrapped); - - QCBOREncode_CloseArray(&EC); - - UsefulBufC Encoded; - if(QCBOREncode_Finish(&EC, &Encoded)) { - return -1; - } - - if(CheckResults(Encoded, spExpectedBstrWrap)) { - return -2; - } - - /* Another test; see about handling length calculation */ - QCBOREncode_Init(&EC, (UsefulBuf){NULL, INT32_MAX}); - QCBOREncode_OpenArray(&EC); - QCBOREncode_BstrWrap(&EC); - QCBOREncode_OpenArray(&EC); - QCBOREncode_AddNULL(&EC); - QCBOREncode_CloseArray(&EC); - UsefulBufC BStr; - QCBOREncode_CloseBstrWrap(&EC, &BStr); - // 2 is one byte for an array of length 1 and 1 byte for a NULL - if(BStr.ptr != NULL || BStr.len != 2) { - return -5; - } - - return 0; -} - - - -int BstrWrapErrorTest() -{ - // -------------- Test closing a bstrwrap when it is an array that is open ----------- - QCBOREncodeContext EC; - - QCBOREncode_Init(&EC, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf)); - - QCBOREncode_OpenArray(&EC); - QCBOREncode_AddUInt64(&EC, 451); - - QCBOREncode_BstrWrap(&EC); - QCBOREncode_AddUInt64(&EC, 466); - QCBOREncode_OpenArray(&EC); - - UsefulBufC Wrapped; - QCBOREncode_CloseBstrWrap(&EC, &Wrapped); - - QCBOREncode_CloseArray(&EC); - - UsefulBufC Encoded2; - if(QCBOREncode_Finish(&EC, &Encoded2) != QCBOR_ERR_CLOSE_MISMATCH) { - return -1; - } - - // ----------- test closing a bstrwrap when nothing is open --------------------- - QCBOREncode_Init(&EC, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf)); - QCBOREncode_CloseBstrWrap(&EC, &Wrapped); - if(QCBOREncode_Finish(&EC, &Encoded2) != QCBOR_ERR_TOO_MANY_CLOSES) { - return -2; - } - - // --------------- test nesting too deep ---------------------------------- - QCBOREncode_Init(&EC, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf)); - for(int i = 1; i < 18; i++) { - QCBOREncode_BstrWrap(&EC); - } - QCBOREncode_AddBool(&EC, true); - - for(int i = 1; i < 18; i++) { - QCBOREncode_CloseBstrWrap(&EC, &Wrapped); - } - - if(QCBOREncode_Finish(&EC, &Encoded2) != QCBOR_ERR_ARRAY_NESTING_TOO_DEEP) { - return -3; - } - - return 0; -} - - - -// Part of bstr_wrap_nest_test -/* - 83 array with three - 53 byte string with 19 bytes - 01 #1 - 50 byte string with 16 bytes - 02 - 4D byte string with 13 bytes - 03 - 4A byte string with 10 bytes - 04 - 47 byte string with 7 bytes - 05 - 44 byte string with 4 bytes - 06 - 41 byte string with 1 byte - 07 - 01 - 02 - 03 - 04 - 05 - 06 - 07 - A2 map with two items - 18 20 label for byte string - 54 byte string of length 20 - 82 Array with two items - 10 The integer value 10 - A2 map with two items - 18 21 label for byte string - 44 byte string with 4 bytes - 81 array with 1 item - 11 integer value 11 - 18 30 integer value 30 - 18 40 integer label 40 - 65 68 65 6C 6C 6F text string hello - 18 31 integer value 31 - 18 41 integer label 41 - 65 68 65 6C 6C 6F text string hello - - - */ - - -/* - 83 # array(3) - 56 # bytes(22) - 00530150024D034A0447054406410700010203040506 # "\x00S\x01P\x02M\x03J\x04G\x05D\x06A\a\x00\x01\x02\x03\x04\x05\x06" - 07 # unsigned(7) - A2 # map(2) - 18 20 # unsigned(32) - 54 # bytes(20) - 8210A21821448111183018406568656C6C6F1831 # "\x82\x10\xA2\x18!D\x81\x11\x180\x18@ehello\x181" - 18 41 # unsigned(65) - 65 # text(5) - 68656C6C6F # "hello" - */ -static const uint8_t spExpectedDeepBstr[] = -{ - 0x83, 0x56, 0x00, 0x53, 0x01, 0x50, 0x02, 0x4D, - 0x03, 0x4A, 0x04, 0x47, 0x05, 0x44, 0x06, 0x41, - 0x07, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, - 0x07, 0xA2, 0x18, 0x20, 0x54, 0x82, 0x10, 0xA2, - 0x18, 0x21, 0x44, 0x81, 0x11, 0x18, 0x30, 0x18, - 0x40, 0x65, 0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x18, - 0x31, 0x18, 0x41, 0x65, 0x68, 0x65, 0x6C, 0x6C, - 0x6F -}; - -// Part of bstr_wrap_nest_test -static int DecodeNextNested(UsefulBufC Wrapped) -{ - int nReturn; - QCBORDecodeContext DC; - QCBORDecode_Init(&DC, Wrapped, QCBOR_DECODE_MODE_NORMAL); - - QCBORItem Item; - nReturn = QCBORDecode_GetNext(&DC, &Item); - if(nReturn) { - return -11; - } - if(Item.uDataType != QCBOR_TYPE_INT64) { - return -12; - } - - nReturn = QCBORDecode_GetNext(&DC, &Item); - if(nReturn == QCBOR_ERR_HIT_END) { - return 0; - } - if(Item.uDataType != QCBOR_TYPE_BYTE_STRING) { - return -13; - } - nReturn = DecodeNextNested(Item.val.string); - if(nReturn) { - return nReturn; - } - - nReturn = QCBORDecode_GetNext(&DC, &Item); - if(nReturn) { - return -14; - } - if(Item.uDataType != QCBOR_TYPE_INT64) { - return -15; - } - - if(QCBORDecode_Finish(&DC)) { - return -16; - } - - return 0; -} - -// Part of bstr_wrap_nest_test -static int DecodeNextNested2(UsefulBufC Wrapped) -{ - int nReturn; - QCBORDecodeContext DC; - QCBORDecode_Init(&DC, Wrapped, QCBOR_DECODE_MODE_NORMAL); - - QCBORItem Item; - nReturn = QCBORDecode_GetNext(&DC, &Item); - if(nReturn) { - return -11; - } - if(Item.uDataType != QCBOR_TYPE_ARRAY) { - return -12; - } - - nReturn = QCBORDecode_GetNext(&DC, &Item); - if(nReturn) { - return -11; - } - if(Item.uDataType != QCBOR_TYPE_INT64) { - return -12; - } - - nReturn = QCBORDecode_GetNext(&DC, &Item); - if(nReturn) { - return -11; - } - if(Item.uDataType != QCBOR_TYPE_MAP) { - return 0; - } - - nReturn = QCBORDecode_GetNext(&DC, &Item); - if(nReturn) { - return -11; - } - if(Item.uDataType != QCBOR_TYPE_BYTE_STRING) { - return -13; - } - nReturn = DecodeNextNested2(Item.val.string); - if(nReturn) { - return nReturn; - } - - nReturn = QCBORDecode_GetNext(&DC, &Item); - if(nReturn) { - return -11; - } - if(Item.uDataType != QCBOR_TYPE_TEXT_STRING) { - return -12; - } - nReturn = QCBORDecode_GetNext(&DC, &Item); - if(nReturn) { - return -11; - } - if(Item.uDataType != QCBOR_TYPE_INT64) { - return -12; - } - - if(QCBORDecode_Finish(&DC)) { - return -16; - } - - return 0; -} - - -int BstrWrapNestTest() -{ - QCBOREncodeContext EC; - QCBOREncode_Init(&EC, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf)); - - // ---- Make a complicated nested CBOR structure --- -#define BSTR_TEST_DEPTH 10 - - QCBOREncode_OpenArray(&EC); - - for(int i = 0; i < BSTR_TEST_DEPTH-2; i++) { - QCBOREncode_BstrWrap(&EC); - QCBOREncode_AddUInt64(&EC, i); - } - - for(int i = 0; i < BSTR_TEST_DEPTH-2; i++) { - QCBOREncode_CloseBstrWrap(&EC, NULL); - QCBOREncode_AddUInt64(&EC, i); - } - - for(int i = 0; i < (BSTR_TEST_DEPTH-2)/3; i++) { - QCBOREncode_OpenMap(&EC); - QCBOREncode_BstrWrapInMapN(&EC, i+0x20); - QCBOREncode_OpenArray(&EC); - QCBOREncode_AddUInt64(&EC, i+0x10); - } - - for(int i = 0; i < (BSTR_TEST_DEPTH-2)/3; i++) { - QCBOREncode_CloseArray(&EC); - QCBOREncode_AddUInt64(&EC, i+0x30); - QCBOREncode_CloseBstrWrap(&EC, NULL); - QCBOREncode_AddSZStringToMapN(&EC, i+0x40, "hello"); - QCBOREncode_CloseMap(&EC); - } - QCBOREncode_CloseArray(&EC); - - UsefulBufC Encoded; - if(QCBOREncode_Finish(&EC, &Encoded)) { - return -1; - } - - // ---Compare it to expected. Expected was hand checked with use of CBOR playground ---- - if(UsefulBuf_Compare(UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedDeepBstr), Encoded)) { - return -25; - } - - - // ---- Decode it and see if it is OK ------ - QCBORDecodeContext DC; - QCBORDecode_Init(&DC, Encoded, QCBOR_DECODE_MODE_NORMAL); - - QCBORItem Item; - QCBORDecode_GetNext(&DC, &Item); - if(Item.uDataType != QCBOR_TYPE_ARRAY || Item.val.uCount != 3) { - return -2; - } - - QCBORDecode_GetNext(&DC, &Item); - if(Item.uDataType != QCBOR_TYPE_BYTE_STRING) { - return -3; - } - - int nReturn = DecodeNextNested(Item.val.string); - if(nReturn) { - return nReturn; - } - - nReturn = QCBORDecode_GetNext(&DC, &Item); - if(nReturn) { - return -11; - } - if(Item.uDataType != QCBOR_TYPE_INT64) { - return -12; - } - - QCBORDecode_GetNext(&DC, &Item); - if(Item.uDataType != QCBOR_TYPE_MAP || Item.val.uCount != 2) { - return -2; - } - - QCBORDecode_GetNext(&DC, &Item); - if(Item.uDataType != QCBOR_TYPE_BYTE_STRING) { - return -3; - } - nReturn = DecodeNextNested2(Item.val.string); - if(nReturn) { - return nReturn; - } - - nReturn = QCBORDecode_GetNext(&DC, &Item); - if(nReturn) { - return -11; - } - if(Item.uDataType != QCBOR_TYPE_TEXT_STRING) { - return -12; - } - - if(QCBORDecode_Finish(&DC)) { - return -16; - } - - return 0; -} - - -static const uint8_t spSignature[] = { - 0x8e, 0xb3, 0x3e, 0x4c, 0xa3, 0x1d, 0x1c, 0x46, 0x5a, 0xb0, - 0x5a, 0xac, 0x34, 0xcc, 0x6b, 0x23, 0xd5, 0x8f, 0xef, 0x5c, - 0x08, 0x31, 0x06, 0xc4, 0xd2, 0x5a, 0x91, 0xae, 0xf0, 0xb0, - 0x11, 0x7e, 0x2a, 0xf9, 0xa2, 0x91, 0xaa, 0x32, 0xe1, 0x4a, - 0xb8, 0x34, 0xdc, 0x56, 0xed, 0x2a, 0x22, 0x34, 0x44, 0x54, - 0x7e, 0x01, 0xf1, 0x1d, 0x3b, 0x09, 0x16, 0xe5, 0xa4, 0xc3, - 0x45, 0xca, 0xcb, 0x36}; - -/* - D2 # tag(18) - 84 # array(4) - 43 # bytes(3) - A10126 # "\xA1\x01&" - A1 # map(1) - 04 # unsigned(4) - 42 # bytes(2) - 3131 # "11" - 54 # bytes(20) - 546869732069732074686520636F6E74656E742E # "This is the content." - 58 40 # bytes(64) - 8EB33E4CA31D1C465AB05AAC34CC6B23D58FEF5C083106C4D25A91AEF0B0117E2AF9A291AA32E14AB834DC56ED2A223444547E01F11D3B0916E5A4C345CACB36 # "\x8E\xB3>L\xA3\x1D\x1CFZ\xB0Z\xAC4\xCCk#\xD5\x8F\xEF\\\b1\x06\xC4\xD2Z\x91\xAE\xF0\xB0\x11~*\xF9\xA2\x91\xAA2\xE1J\xB84\xDCV\xED*\"4DT~\x01\xF1\x1D;\t\x16\xE5\xA4\xC3E\xCA\xCB6" - */ -static const uint8_t spExpected[] = { - 0xD2, 0x84, 0x43, 0xA1, 0x01, 0x26, 0xA1, 0x04, 0x42, 0x31, - 0x31, 0x54, 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, - 0x74, 0x68, 0x65, 0x20, 0x63, 0x6F, 0x6E, 0x74, 0x65, 0x6E, - 0x74, 0x2E, 0x58, 0x40, 0x8E, 0xB3, 0x3E, 0x4C, 0xA3, 0x1D, - 0x1C, 0x46, 0x5A, 0xB0, 0x5A, 0xAC, 0x34, 0xCC, 0x6B, 0x23, - 0xD5, 0x8F, 0xEF, 0x5C, 0x08, 0x31, 0x06, 0xC4, 0xD2, 0x5A, - 0x91, 0xAE, 0xF0, 0xB0, 0x11, 0x7E, 0x2A, 0xF9, 0xA2, 0x91, - 0xAA, 0x32, 0xE1, 0x4A, 0xB8, 0x34, 0xDC, 0x56, 0xED, 0x2A, - 0x22, 0x34, 0x44, 0x54, 0x7E, 0x01, 0xF1, 0x1D, 0x3B, 0x09, - 0x16, 0xE5, 0xA4, 0xC3, 0x45, 0xCA, 0xCB, 0x36}; - -/* - this corresponds exactly to the example in RFC 8152 - section C.2.1. This doesn't actually verify the signature - though that would be nice as it would make the test - really good. That would require bring in ECDSA crypto - to this test. - */ -int CoseSign1TBSTest() -{ - // All of this is from RFC 8152 C.2.1 - const char *szKid = "11"; - const UsefulBufC Kid = UsefulBuf_FromSZ(szKid); - const char *szPayload = "This is the content."; - const UsefulBufC Payload = UsefulBuf_FromSZ(szPayload); - static const uint8_t pProtectedHeaders[] = {0xa1, 0x01, 0x26}; - const UsefulBufC ProtectedHeaders = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pProtectedHeaders); - - // It would be good to compare this to the output from - // a COSE implementation like COSE-C. It has been checked - // against the CBOR playground. - const UsefulBufC Signature = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spSignature); - - QCBOREncodeContext EC; - QCBOREncode_Init(&EC, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf)); - - // top level array for cose sign1, 18 is the tag for COSE sign - QCBOREncode_AddTag(&EC, CBOR_TAG_COSE_SIGN1); - QCBOREncode_OpenArray(&EC); - - // Add protected headers - QCBOREncode_AddBytes(&EC, ProtectedHeaders); - - // Empty map with unprotected headers - QCBOREncode_OpenMap(&EC); - QCBOREncode_AddBytesToMapN(&EC, 4, Kid); - QCBOREncode_CloseMap(&EC); - - // The payload - UsefulBufC WrappedPayload; - QCBOREncode_BstrWrap(&EC); - QCBOREncode_AddEncoded(&EC, Payload); // Payload is not actually CBOR in example C.2.1 - QCBOREncode_CloseBstrWrap(&EC, &WrappedPayload); - - // Check we got back the actual payload expected - if(UsefulBuf_Compare(WrappedPayload, Payload)) { - return -1; - } - - // The signature - QCBOREncode_AddBytes(&EC, Signature); - QCBOREncode_CloseArray(&EC); - - // Finish and check the results - UsefulBufC COSE_Sign1; - if(QCBOREncode_Finish(&EC, &COSE_Sign1)) { - return -2; - } - - // 98 is the size from RFC 8152 C.2.1 - if(COSE_Sign1.len != 98) { - return -3; - } - - if(CheckResults(COSE_Sign1, spExpected)) { - return -4; - } - - return 0; -} - - -int EncodeErrorTests() -{ - QCBOREncodeContext EC; - - - // ------ Test for QCBOR_ERR_BUFFER_TOO_LARGE ------ - // Do all of these tests with NULL buffers so no actual large allocations are neccesary - UsefulBuf Buffer = (UsefulBuf){NULL, UINT32_MAX}; - - // First verify no error from a big buffer - QCBOREncode_Init(&EC, Buffer); - QCBOREncode_OpenArray(&EC); - // 6 is the CBOR overhead for opening the array and encodng the length - // This exactly fills the buffer. - QCBOREncode_AddBytes(&EC, (UsefulBufC){NULL, UINT32_MAX-6}); - QCBOREncode_CloseArray(&EC); - size_t xx; - if(QCBOREncode_FinishGetSize(&EC, &xx) != QCBOR_SUCCESS) { - return -1; - } - - // Second verify error from an array in encoded output too large - QCBOREncode_Init(&EC, Buffer); - QCBOREncode_OpenArray(&EC); - QCBOREncode_AddBytes(&EC, (UsefulBufC){NULL, UINT32_MAX-6}); - QCBOREncode_OpenArray(&EC); // Where QCBOR internally encounters and records error - QCBOREncode_CloseArray(&EC); - QCBOREncode_CloseArray(&EC); - if(QCBOREncode_FinishGetSize(&EC, &xx) != QCBOR_ERR_BUFFER_TOO_LARGE) { - return -2; - } - - // Third, fit an array in exactly at max position allowed - QCBOREncode_Init(&EC, Buffer); - QCBOREncode_OpenArray(&EC); - QCBOREncode_AddBytes(&EC, (UsefulBufC){NULL, QCBOR_MAX_ARRAY_OFFSET-6}); - QCBOREncode_OpenArray(&EC); - QCBOREncode_CloseArray(&EC); - QCBOREncode_CloseArray(&EC); - if(QCBOREncode_FinishGetSize(&EC, &xx) != QCBOR_SUCCESS) { - return -10; - } - - - // ----- QCBOR_ERR_BUFFER_TOO_SMALL -------------- - // Work close to the 4GB size limit for a better test - const uint32_t uLargeSize = UINT32_MAX - 1024; - UsefulBuf Large = (UsefulBuf){NULL,uLargeSize}; - - QCBOREncode_Init(&EC, Large); - QCBOREncode_OpenArray(&EC); - QCBOREncode_AddBytes(&EC, (UsefulBufC){NULL, uLargeSize/2 + 1}); - QCBOREncode_CloseArray(&EC); - if(QCBOREncode_FinishGetSize(&EC, &xx) != QCBOR_SUCCESS) { - // Making sure it succeeds when it should first - return -3; - } - - QCBOREncode_Init(&EC, Large); - QCBOREncode_OpenArray(&EC); - QCBOREncode_AddBytes(&EC, (UsefulBufC){NULL, uLargeSize/2 + 1}); - QCBOREncode_AddBytes(&EC, (UsefulBufC){NULL, uLargeSize/2}); - QCBOREncode_CloseArray(&EC); - if(QCBOREncode_FinishGetSize(&EC, &xx) != QCBOR_ERR_BUFFER_TOO_SMALL) { - // Now just 1 byte over, see that it fails - return -4; - } - - - // ----- QCBOR_ERR_ARRAY_NESTING_TOO_DEEP ------- - QCBOREncode_Init(&EC, Large); - for(int i = QCBOR_MAX_ARRAY_NESTING; i > 0; i--) { - QCBOREncode_OpenArray(&EC); - } - for(int i = QCBOR_MAX_ARRAY_NESTING; i > 0; i--) { - QCBOREncode_CloseArray(&EC); - } - if(QCBOREncode_FinishGetSize(&EC, &xx) != QCBOR_SUCCESS) { - // Making sure it succeeds when it should first - return -5; - } - - QCBOREncode_Init(&EC, Large); - for(int i = QCBOR_MAX_ARRAY_NESTING+1; i > 0; i--) { - QCBOREncode_OpenArray(&EC); - } - for(int i = QCBOR_MAX_ARRAY_NESTING+1; i > 0; i--) { - QCBOREncode_CloseArray(&EC); - } - if(QCBOREncode_FinishGetSize(&EC, &xx) != QCBOR_ERR_ARRAY_NESTING_TOO_DEEP) { - // One more level to cause error - return -6; - } - - - // ------ QCBOR_ERR_TOO_MANY_CLOSES -------- - QCBOREncode_Init(&EC, Large); - for(int i = QCBOR_MAX_ARRAY_NESTING; i > 0; i--) { - QCBOREncode_OpenArray(&EC); - } - for(int i = QCBOR_MAX_ARRAY_NESTING+1; i > 0; i--) { - QCBOREncode_CloseArray(&EC); - } - if(QCBOREncode_FinishGetSize(&EC, &xx) != QCBOR_ERR_TOO_MANY_CLOSES) { - // One more level to cause error - return -7; - } - - - // ------ QCBOR_ERR_CLOSE_MISMATCH -------- - QCBOREncode_Init(&EC, Large); - QCBOREncode_OpenArray(&EC); - UsefulBufC Wrap; - QCBOREncode_CloseBstrWrap(&EC, &Wrap); - if(QCBOREncode_FinishGetSize(&EC, &xx) != QCBOR_ERR_CLOSE_MISMATCH) { - return -8; - } - - - // ------ QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN --------- - QCBOREncode_Init(&EC, Large); - for(int i = QCBOR_MAX_ARRAY_NESTING; i > 0; i--) { - QCBOREncode_OpenArray(&EC); - } - for(int i = QCBOR_MAX_ARRAY_NESTING-1; i > 0; i--) { - QCBOREncode_CloseArray(&EC); - } - if(QCBOREncode_FinishGetSize(&EC, &xx) != QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN) { - // One more level to cause error - return -9; - } - - /* QCBOR_ERR_ARRAY_TOO_LONG is not tested here as - it would require a 64KB of RAM to test */ - - return 0; -} - diff --git a/components/TARGET_PSA/services/attestation/qcbor/test/qcbor_encode_tests.h b/components/TARGET_PSA/services/attestation/qcbor/test/qcbor_encode_tests.h deleted file mode 100644 index 49362c6..0000000 --- a/components/TARGET_PSA/services/attestation/qcbor/test/qcbor_encode_tests.h +++ /dev/null @@ -1,146 +0,0 @@ -/*============================================================================== - Copyright (c) 2016-2018, The Linux Foundation. - Copyright (c) 2018-2019, Laurence Lundblade. - All rights reserved. - SPDX-License-Identifier: BSD-3-Clause - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of The Linux Foundation nor the names of its - contributors, nor the name "Laurence Lundblade" may be used to - endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED -WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT -ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS -BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE -OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN -IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ==============================================================================*/ - -#ifndef __QCBOR__qcbor_encode_tests__ -#define __QCBOR__qcbor_encode_tests__ - -#include "qcbor.h" - - -/* - Notes: - - - All the functions in qcbor.h are called once in the aggregation of all the tests below. - - - All the types that are supported are given as input and parsed by these tests - - - There is some hostile input such as invalid lengths and CBOR too complex - and types this parser doesn't handle - - */ - - -/* - Most basic test. - */ -int BasicEncodeTest(void); - - -/* - Encode lots of integer values, particularly around the boundary and make sure they - Match the expected binary output. Primarily an encoding test. - */ -int IntegerValuesTest1(void); - - - -/* - Create nested arrays to the max depth allowed and make sure it succeeds. - This is an encoding test. - */ -int ArrayNestingTest1(void); - - -/* - Create nested arrays to one more than the meax depth and make sure it fails. - This is an encoding test. - */ -int ArrayNestingTest2(void); - - -/* - Encoding test. - Create arrays to max depth and close one extra time and look for correct error code - */ -int ArrayNestingTest3(void); - - -/* - This tests the QCBOREncode_AddRaw() function by adding two chunks or RAWCBOR to an - array and comparing with expected values. This is an encoding test. - */ -int EncodeRawTest(void); - - -/* - This creates a somewhat complicated CBOR MAP and verifies it against expected - data. This is an encoding test. - */ -int MapEncodeTest(void); - - - -/* - Encodes a goodly number of floats and doubles and checks encoding is right - */ -int FloatValuesTest1(void); - - -/* - Encodes true, false and the like - */ -int SimpleValuesTest1(void); - - -/* - Encodes most data formats that are supported */ -int EncodeDateTest(void); - - -/* - Encodes particular data structure that a particular app will need... - */ -int RTICResultsTest(void); - - -/* - Calls all public encode methods in qcbor.h once. - */ -int AllAddMethodsTest(void); - -/* - The binary string wrapping of maps and arrays used by COSE - */ -int BstrWrapTest(void); - -int BstrWrapErrorTest(void); - -int BstrWrapNestTest(void); - -int CoseSign1TBSTest(void); - -int EncodeErrorTests(void); - - - -#endif /* defined(__QCBOR__qcbor_encode_tests__) */ diff --git a/components/TARGET_PSA/services/attestation/qcbor/test/run_tests.c b/components/TARGET_PSA/services/attestation/qcbor/test/run_tests.c deleted file mode 100644 index 6e35620..0000000 --- a/components/TARGET_PSA/services/attestation/qcbor/test/run_tests.c +++ /dev/null @@ -1,285 +0,0 @@ -/*============================================================================== - run_tests.c -- test aggregator and results reporting - - Copyright (c) 2018-2019, Laurence Lundblade. All rights reserved. - - SPDX-License-Identifier: BSD-3-Clause - - See BSD-3-Clause license in README.md - - Created on 9/30/18 - ==============================================================================*/ - -#include "run_tests.h" -#include "UsefulBuf.h" -#include - -#include "float_tests.h" -#include "qcbor_decode_tests.h" -#include "qcbor_encode_tests.h" -#include "UsefulBuf_Tests.h" - - - -// Used to test RunTests -int fail_test() -{ - return -44; -} - - - - -/* - Convert a number up to 999999999 to a string. This is so sprintf doesn't - have to be linked in so as to minimized dependencies even in test code. - */ -const char *NumToString(int32_t nNum, UsefulBuf StringMem) -{ - const int32_t nMax = 1000000000; - - UsefulOutBuf OutBuf; - UsefulOutBuf_Init(&OutBuf, StringMem); - - if(nNum < 0) { - UsefulOutBuf_AppendByte(&OutBuf, '-'); - nNum = -nNum; - } - if(nNum > nMax-1) { - return "XXX"; - } - - bool bDidSomeOutput = false; - for(int n = nMax; n > 0; n/=10) { - int x = nNum/n; - if(x || bDidSomeOutput){ - bDidSomeOutput = true; - UsefulOutBuf_AppendByte(&OutBuf, '0' + x); - nNum -= x * n; - } - } - if(!bDidSomeOutput){ - UsefulOutBuf_AppendByte(&OutBuf, '0'); - } - UsefulOutBuf_AppendByte(&OutBuf, '\0'); - - return UsefulOutBuf_GetError(&OutBuf) ? "" : StringMem.ptr; -} - - - - -typedef int (test_fun_t)(void); -typedef const char * (test_fun2_t)(void); - - -#define TEST_ENTRY(test_name) {#test_name, test_name, true} -#define TEST_ENTRY_DISABLED(test_name) {#test_name, test_name, false} - -typedef struct { - const char *szTestName; - test_fun_t *test_fun; - bool bEnabled; -} test_entry; - -typedef struct { - const char *szTestName; - test_fun2_t *test_fun; - bool bEnabled; -} test_entry2; - -test_entry2 s_tests2[] = { - TEST_ENTRY(UBUTest_CopyUtil), - TEST_ENTRY(UOBTest_NonAdversarial), - TEST_ENTRY(TestBasicSanity), - TEST_ENTRY(UOBTest_BoundaryConditionsTest), - TEST_ENTRY(UBMacroConversionsTest), - TEST_ENTRY(UBUtilTests), - TEST_ENTRY(UIBTest_IntegerFormat) -}; - - -test_entry s_tests[] = { - TEST_ENTRY(ParseMapAsArrayTest), - TEST_ENTRY_DISABLED(AllocAllStringsTest), - TEST_ENTRY(IndefiniteLengthNestTest), - TEST_ENTRY(NestedMapTestIndefLen), - TEST_ENTRY(ParseSimpleTest), - TEST_ENTRY(EncodeRawTest), - TEST_ENTRY(RTICResultsTest), - TEST_ENTRY(MapEncodeTest), - TEST_ENTRY(ArrayNestingTest1), - TEST_ENTRY(ArrayNestingTest2), - TEST_ENTRY(ArrayNestingTest3), - TEST_ENTRY(EncodeDateTest), - TEST_ENTRY(SimpleValuesTest1), - TEST_ENTRY(IntegerValuesTest1), - TEST_ENTRY(AllAddMethodsTest), - TEST_ENTRY(ParseTooDeepArrayTest), - TEST_ENTRY(ComprehensiveInputTest), - TEST_ENTRY(ParseMapTest), - TEST_ENTRY_DISABLED(IndefiniteLengthArrayMapTest), - TEST_ENTRY(BasicEncodeTest), - TEST_ENTRY(NestedMapTest), - TEST_ENTRY(BignumParseTest), - TEST_ENTRY(OptTagParseTest), - TEST_ENTRY(DateParseTest), - TEST_ENTRY(ShortBufferParseTest2), - TEST_ENTRY(ShortBufferParseTest), - TEST_ENTRY(ParseDeepArrayTest), - TEST_ENTRY(SimpleArrayTest), - TEST_ENTRY(IntegerValuesParseTest), - TEST_ENTRY_DISABLED(MemPoolTest), - TEST_ENTRY_DISABLED(IndefiniteLengthStringTest), - TEST_ENTRY(HalfPrecisionDecodeBasicTests), - TEST_ENTRY(DoubleAsSmallestTest), - TEST_ENTRY(HalfPrecisionAgainstRFCCodeTest), - TEST_ENTRY(BstrWrapTest), - TEST_ENTRY(BstrWrapErrorTest), - TEST_ENTRY(BstrWrapNestTest), - TEST_ENTRY(CoseSign1TBSTest), - TEST_ENTRY(StringDecoderModeFailTest), - TEST_ENTRY_DISABLED(BigComprehensiveInputTest), - TEST_ENTRY(EncodeErrorTests), - //TEST_ENTRY(fail_test), -}; - - -int RunTests(const char *szTestNames[], OutputStringCB pfOutput, void *poutCtx, int *pNumTestsRun) -{ - int nTestsFailed = 0; - int nTestsRun = 0; - UsefulBuf_MAKE_STACK_UB(StringStorage, 5); - - test_entry2 *t2; - const test_entry2 *s_tests2_end = s_tests2 + sizeof(s_tests2)/sizeof(test_entry2); - - for(t2 = s_tests2; t2 < s_tests2_end; t2++) { - if(szTestNames[0]) { - // Some tests have been named - const char **szRequestedNames; - for(szRequestedNames = szTestNames; *szRequestedNames; szRequestedNames++) { - if(!strcmp(t2->szTestName, *szRequestedNames)) { - break; // Name matched - } - } - if(*szRequestedNames == NULL) { - // Didn't match this test - continue; - } - } else { - // no tests named, but don't run "disabled" tests - if(!t2->bEnabled) { - // Don't run disabled tests when all tests are being run - // as indicated by no specific test names being given - continue; - } - } - - const char * szTestResult = (t2->test_fun)(); - nTestsRun++; - if(pfOutput) { - (*pfOutput)(t2->szTestName, poutCtx, 0); - } - - if(szTestResult) { - if(pfOutput) { - (*pfOutput)(" FAILED (returned ", poutCtx, 0); - (*pfOutput)(szTestResult, poutCtx, 0); - (*pfOutput)(")", poutCtx, 1); - } - nTestsFailed++; - } else { - if(pfOutput) { - (*pfOutput)( " PASSED", poutCtx, 1); - } - } - } - - - test_entry *t; - const test_entry *s_tests_end = s_tests + sizeof(s_tests)/sizeof(test_entry); - - for(t = s_tests; t < s_tests_end; t++) { - if(szTestNames[0]) { - // Some tests have been named - const char **szRequestedNames; - for(szRequestedNames = szTestNames; *szRequestedNames; szRequestedNames++) { - if(!strcmp(t->szTestName, *szRequestedNames)) { - break; // Name matched - } - } - if(*szRequestedNames == NULL) { - // Didn't match this test - continue; - } - } else { - // no tests named, but don't run "disabled" tests - if(!t->bEnabled) { - // Don't run disabled tests when all tests are being run - // as indicated by no specific test names being given - continue; - } - } - - int nTestResult = (t->test_fun)(); - nTestsRun++; - if(pfOutput) { - (*pfOutput)(t->szTestName, poutCtx, 0); - } - - if(nTestResult) { - if(pfOutput) { - (*pfOutput)(" FAILED (returned ", poutCtx, 0); - (*pfOutput)(NumToString(nTestResult, StringStorage), poutCtx, 0); - (*pfOutput)(")", poutCtx, 1); - } - nTestsFailed++; - } else { - if(pfOutput) { - (*pfOutput)( " PASSED", poutCtx, 1); - } - } - } - - if(pNumTestsRun) { - *pNumTestsRun = nTestsRun; - } - - if(pfOutput) { - (*pfOutput)( "SUMMARY: ", poutCtx, 0); - (*pfOutput)( NumToString(nTestsRun, StringStorage), poutCtx, 0); - (*pfOutput)( " tests run; ", poutCtx, 0); - (*pfOutput)( NumToString(nTestsFailed, StringStorage), poutCtx, 0); - (*pfOutput)( " tests failed", poutCtx, 1); - } - - return nTestsFailed; -} - - - - -static void PrintSize(const char *szWhat, uint32_t uSize, OutputStringCB pfOutput, void *pOutCtx) -{ - UsefulBuf_MAKE_STACK_UB(buffer, 20); - - (*pfOutput)(szWhat, pOutCtx, 0); - (*pfOutput)(" ", pOutCtx, 0); - (*pfOutput)(NumToString(uSize, buffer), pOutCtx, 0); - (*pfOutput)("", pOutCtx, 1); -} - -void PrintSizes(OutputStringCB pfOutput, void *pOutCtx) -{ - // Type and size of return from sizeof() varies. These will never be large so cast is safe - PrintSize("sizeof(QCBORTrackNesting)", (uint32_t)sizeof(QCBORTrackNesting), pfOutput, pOutCtx); - PrintSize("sizeof(QCBOREncodeContext)", (uint32_t)sizeof(QCBOREncodeContext), pfOutput, pOutCtx); - PrintSize("sizeof(QCBORDecodeNesting)", (uint32_t)sizeof(QCBORDecodeNesting), pfOutput, pOutCtx); - PrintSize("sizeof(QCBORDecodeContext)", (uint32_t)sizeof(QCBORDecodeContext), pfOutput, pOutCtx); - PrintSize("sizeof(QCBORItem)", (uint32_t)sizeof(QCBORItem), pfOutput, pOutCtx); - PrintSize("sizeof(QCBORStringAllocator)",(uint32_t)sizeof(QCBORStringAllocator), pfOutput, pOutCtx); - PrintSize("sizeof(QCBORTagListIn)", (uint32_t)sizeof(QCBORTagListIn), pfOutput, pOutCtx); - PrintSize("sizeof(QCBORTagListOut)", (uint32_t)sizeof(QCBORTagListOut), pfOutput, pOutCtx); - (*pfOutput)("", pOutCtx, 1); -} diff --git a/components/TARGET_PSA/services/attestation/qcbor/test/run_tests.h b/components/TARGET_PSA/services/attestation/qcbor/test/run_tests.h deleted file mode 100644 index 734d4f8..0000000 --- a/components/TARGET_PSA/services/attestation/qcbor/test/run_tests.h +++ /dev/null @@ -1,66 +0,0 @@ -/*============================================================================== - run_tests.h -- test aggregator and results reporting - - Copyright (c) 2018-2019, Laurence Lundblade. All rights reserved. - - SPDX-License-Identifier: BSD-3-Clause - - See BSD-3-Clause license in README.md - - Created 9/30/18 - ==============================================================================*/ - -/** - @file run_tests.h -*/ - -/** - @brief Type for function to output a text string - - @param[in] szString The string to output - @param[in] pOutCtx A context pointer; NULL if not needed - @param[in] bNewline If non-zero, output a newline after the string - - This is a prototype of a function to be passed to RunTests() to - output text strings. - - This can be implemented with stdio (if available) using a straight - call to fputs() where the FILE * is passed as the pOutCtx as shown in - the example code below. This code is for Linux where the newline is - a \\n. Windows usually prefers \\r\\n. - - @code - static void fputs_wrapper(const char *szString, void *pOutCtx, int bNewLine) - { - fputs(szString, (FILE *)pOutCtx); - if(bNewLine) { - fputs("\n", pOutCtx); - } - } - @endcode -*/ -typedef void (*OutputStringCB)(const char *szString, void *pOutCtx, int bNewline); - - -/** - @brief Runs the QCBOR tests. - - @param[in] szTestNames An argv-style list of test names to run. If - empty, all are run. - @param[in] pfOutput Function that is called to output text strings. - @param[in] pOutCtx Context pointer passed to output function. - @param[out] pNumTestsRun Returns the number of tests run. May be NULL. - - @return The number of tests that failed. Zero means overall success. - */ -int RunTests(const char *szTestNames[], OutputStringCB pfOutput, void *pOutCtx, int *pNumTestsRun); - - -/** - @brief Print sizes of encoder / decoder contexts. - - @param[in] pfOutput Function that is called to output text strings. - @param[in] pOutCtx Context pointer passed to output function. - */ -void PrintSizes(OutputStringCB pfOutput, void *pOutCtx); - diff --git a/components/TARGET_PSA/services/attestation/tfm_client.h b/components/TARGET_PSA/services/attestation/tfm_client.h deleted file mode 100755 index ee2645d..0000000 --- a/components/TARGET_PSA/services/attestation/tfm_client.h +++ /dev/null @@ -1,32 +0,0 @@ -/* -* Copyright (c) 2018-2019 ARM Limited. All rights reserved. -* -* SPDX-License-Identifier: Apache-2.0 -* -* Licensed under the Apache License, Version 2.0 (the License); you may -* not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an AS IS BASIS, WITHOUT -* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#ifndef __TFM_CLIENT_H__ -#define __TFM_CLIENT_H__ - -#include "psa/client.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#ifdef __cplusplus -} -#endif - -#endif /* __TFM_CLIENT_H__ */ diff --git a/components/TARGET_PSA/services/crypto/COMPONENT_PSA_SRV_IPC/crypto_platform_spe.h b/components/TARGET_PSA/services/crypto/COMPONENT_PSA_SRV_IPC/crypto_platform_spe.h deleted file mode 100644 index 05fe728..0000000 --- a/components/TARGET_PSA/services/crypto/COMPONENT_PSA_SRV_IPC/crypto_platform_spe.h +++ /dev/null @@ -1,179 +0,0 @@ -/** - * \file psa/crypto_platform_spe.h - * - * \brief PSA cryptography module: Mbed TLS platfom definitions - */ -/* - * Copyright (C) 2018, ARM Limited, All Rights Reserved - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * This file is part of mbed TLS (https://tls.mbed.org) - */ - -#ifndef PSA_CRYPTO_SPE_PLATFORM_H -#define PSA_CRYPTO_SPE_PLATFORM_H - -/* Include the Mbed TLS configuration file, the way Mbed TLS does it - * in each of its header files. */ -#if !defined(MBEDTLS_CONFIG_FILE) -#include "../mbedtls/config.h" -#else -#include MBEDTLS_CONFIG_FILE -#endif - -/** \defgroup PSA Crypto APIs -* @{ -*/ - -/** \brief psa_s_function_t enum defines for all the available functions in PSA Crypto. */ -typedef enum psa_sec_function_s { - PSA_CRYPTO_INVALID, - PSA_GET_KEY_ATTRIBUTES, - PSA_OPEN_KEY, - PSA_CLOSE_KEY, - PSA_IMPORT_KEY, - PSA_DESTROY_KEY, - PSA_EXPORT_KEY, - PSA_EXPORT_PUBLIC_KEY, - PSA_COPY_KEY, - PSA_HASH_COMPUTE, - PSA_HASH_COMPARE, - PSA_HASH_SETUP, - PSA_HASH_UPDATE, - PSA_HASH_FINISH, - PSA_HASH_VERIFY, - PSA_HASH_ABORT, - PSA_HASH_CLONE, - PSA_HASH_CLONE_BEGIN, - PSA_HASH_CLONE_END, - PSA_MAC_COMPUTE, - PSA_MAC_VERIFY, - PSA_MAC_SIGN_SETUP, - PSA_MAC_VERIFY_SETUP, - PSA_MAC_UPDATE, - PSA_MAC_SIGN_FINISH, - PSA_MAC_VERIFY_FINISH, - PSA_MAC_ABORT, - PSA_CIPHER_ENCRYPT, - PSA_CIPHER_DECRYPT, - PSA_CIPHER_ENCRYPT_SETUP, - PSA_CIPHER_DECRYPT_SETUP, - PSA_CIPHER_GENERATE_IV, - PSA_CIPHER_SET_IV, - PSA_CIPHER_UPDATE, - PSA_CIPHER_FINISH, - PSA_CIPHER_ABORT, - PSA_AEAD_ENCRYPT, - PSA_AEAD_DECRYPT, - PSA_AEAD_ENCRYPT_SETUP, - PSA_AEAD_DECRYPT_SETUP, - PSA_AEAD_GENERATE_NONCE, - PSA_AEAD_SET_NONCE, - PSA_AEAD_SET_LENGTHS, - PSA_AEAD_UPDATE_AD, - PSA_AEAD_UPDATE, - PSA_AEAD_FINISH, - PSA_AEAD_VERIFY, - PSA_AEAD_ABORT, - PSA_SIGN_HASH, - PSA_VERIFY_HASH, - PSA_ASYMMETRIC_ENCRYPT, - PSA_ASYMMETRIC_DECRYPT, - PSA_KEY_DERIVATION_SETUP, - PSA_KEY_DERIVATION_GET_CAPACITY, - PSA_KEY_DERIVATION_SET_CAPACITY, - PSA_KEY_DERIVATION_INPUT_BYTES, - PSA_KEY_DERIVATION_INPUT_KEY, - PSA_KEY_DERIVATION_KEY_AGREEMENT, - PSA_KEY_DERIVATION_OUTPUT_BYTES, - PSA_KEY_DERIVATION_OUTPUT_KEY, - PSA_KEY_DERIVATION_ABORT, - PSA_RAW_KEY_AGREEMENT, - PSA_GENERATE_RANDOM, - PSA_GENERATE_KEY, -} psa_sec_function_t; - -/**@}*/ - -/** \defgroup PSA Crypto structures for IPC -* @{ -*/ - -/** psa_crypto_ipc_s struct used for some of the - * PSA Crypto APIs that need psa_key_handle_t and psa_algorithm_t arguments - * and in order to use the existing infrastructure of the SPM-IPC we provide a struct to - * pack them together. - */ -typedef struct psa_crypto_ipc_s { - psa_sec_function_t func; - psa_key_handle_t handle; - psa_algorithm_t alg; -} psa_crypto_ipc_t; - -/** psa_crypto_derivation_ipc_s struct used for some of the - * PSA Crypto APIs that need psa_key_handle_t and psa_algorithm_t arguments - * and in order to use the existing infrastructure of the SPM-IPC we provide a struct to - * pack them together. - */ -typedef struct psa_crypto_derivation_ipc_s { - psa_sec_function_t func; - psa_key_handle_t handle; - psa_algorithm_t alg; - size_t capacity; -} psa_crypto_derivation_ipc_t; - -/** psa_key_mng_ipc_s struct used for some of the - * PSA Crypto APIs that need psa_key_handle_t and psa_algorithm_t arguments - * and in order to use the existing infrastructure of the SPM-IPC we provide a struct to - * pack them together. - */ -typedef struct psa_key_mng_ipc_s { - psa_key_handle_t handle; - psa_sec_function_t func; -} psa_key_mng_ipc_t; - -/** psa_crypto_ipc_aead_s struct used for AEAD integrated - * PSA Crypto APIs that need psa_key_handle_t and psa_algorithm_t and extra arguments - * and in order to use the existing infrastructure of the SPM-IPC we provide a struct to - * pack them together. - */ -// Max length supported for nonce is 16 bytes. -#define PSA_AEAD_MAX_NONCE_SIZE 16 -typedef struct psa_crypto_ipc_aead_s { - psa_sec_function_t func; - psa_key_handle_t handle; - psa_algorithm_t alg; - uint16_t nonce_size; - size_t additional_data_length; - size_t input_length; - uint8_t nonce[PSA_AEAD_MAX_NONCE_SIZE]; -} psa_crypto_ipc_aead_t; - -/** psa_crypto_ipc_asymmetric_s struct used for asymmetric - * PSA Crypto APIs that need psa_key_handle_t and psa_algorithm_t arguments - * and in order to use the existing infrastructure of the SPM-IPC we provide a struct to - * pack them together. - */ -typedef struct psa_crypto_ipc_asymmetric_s { - psa_sec_function_t func; - psa_key_handle_t handle; - psa_algorithm_t alg; - size_t input_length; - size_t salt_length; -} psa_crypto_ipc_asymmetric_t; - -/**@}*/ - -#endif /* PSA_CRYPTO_SPE_PLATFORM_H */ diff --git a/components/TARGET_PSA/services/crypto/COMPONENT_PSA_SRV_IPC/crypto_struct.h b/components/TARGET_PSA/services/crypto/COMPONENT_PSA_SRV_IPC/crypto_struct.h deleted file mode 100644 index 465ccbb..0000000 --- a/components/TARGET_PSA/services/crypto/COMPONENT_PSA_SRV_IPC/crypto_struct.h +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright (c) 2020, Arm Limited and affiliates. - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include "crypto_struct_ipc.h" diff --git a/components/TARGET_PSA/services/crypto/COMPONENT_PSA_SRV_IPC/crypto_struct_ipc.h b/components/TARGET_PSA/services/crypto/COMPONENT_PSA_SRV_IPC/crypto_struct_ipc.h deleted file mode 100644 index 20bea21..0000000 --- a/components/TARGET_PSA/services/crypto/COMPONENT_PSA_SRV_IPC/crypto_struct_ipc.h +++ /dev/null @@ -1,318 +0,0 @@ -/** - * \file psa/crypto_struct.h - * - * \brief PSA cryptography module: Mbed TLS structured type implementations - * - * \note This file may not be included directly. Applications must - * include psa/crypto.h. - * - * This file contains the definitions of some data structures with - * implementation-specific definitions. - * - * In implementations with isolation between the application and the - * cryptography module, it is expected that the front-end and the back-end - * would have different versions of this file. - * - *

Design notes about multipart operation structures

- * - * Each multipart operation structure contains a `psa_algorithm_t alg` - * field which indicates which specific algorithm the structure is for. - * When the structure is not in use, `alg` is 0. Most of the structure - * consists of a union which is discriminated by `alg`. - * - * Note that when `alg` is 0, the content of other fields is undefined. - * In particular, it is not guaranteed that a freshly-initialized structure - * is all-zero: we initialize structures to something like `{0, 0}`, which - * is only guaranteed to initializes the first member of the union; - * GCC and Clang initialize the whole structure to 0 (at the time of writing), - * but MSVC and CompCert don't. - * - * In Mbed Crypto, multipart operation structures live independently from - * the key. This allows Mbed Crypto to free the key objects when destroying - * a key slot. If a multipart operation needs to remember the key after - * the setup function returns, the operation structure needs to contain a - * copy of the key. - */ -/* - * Copyright (C) 2018, ARM Limited, All Rights Reserved - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * This file is part of mbed TLS (https://tls.mbed.org) - */ - -#ifndef PSA_CRYPTO_STRUCT_H -#define PSA_CRYPTO_STRUCT_H - -#include "psa/client.h" - -#ifdef __cplusplus -extern "C" { -#endif - -struct psa_hash_operation_s { - psa_handle_t handle; -}; - -#define PSA_HASH_OPERATION_INIT { PSA_NULL_HANDLE } -static inline struct psa_hash_operation_s psa_hash_operation_init( void ) -{ - const struct psa_hash_operation_s v = PSA_HASH_OPERATION_INIT; - return( v ); -} - -struct psa_mac_operation_s -{ - psa_handle_t handle; -}; - -#define PSA_MAC_OPERATION_INIT { PSA_NULL_HANDLE } -static inline struct psa_mac_operation_s psa_mac_operation_init( void ) -{ - const struct psa_mac_operation_s v = PSA_MAC_OPERATION_INIT; - return( v ); -} - -struct psa_cipher_operation_s -{ - psa_handle_t handle; -}; - -#define PSA_CIPHER_OPERATION_INIT { PSA_NULL_HANDLE } -static inline struct psa_cipher_operation_s psa_cipher_operation_init( void ) -{ - const struct psa_cipher_operation_s v = PSA_CIPHER_OPERATION_INIT; - return( v ); -} - -struct psa_aead_operation_s -{ - psa_handle_t handle; -}; - -#define PSA_AEAD_OPERATION_INIT { PSA_NULL_HANDLE } -static inline struct psa_aead_operation_s psa_aead_operation_init( void ) -{ - const struct psa_aead_operation_s v = PSA_AEAD_OPERATION_INIT; - return( v ); -} - -struct psa_key_derivation_s -{ - psa_handle_t handle; -}; - -/* This only zeroes out the first byte in the union, the rest is unspecified. */ -#define PSA_KEY_DERIVATION_OPERATION_INIT { PSA_NULL_HANDLE } -static inline struct psa_key_derivation_s psa_key_derivation_operation_init( void ) -{ - const struct psa_key_derivation_s v = PSA_KEY_DERIVATION_OPERATION_INIT; - return( v ); -} - -struct psa_key_policy_s -{ - psa_key_usage_t usage; - psa_algorithm_t alg; - psa_algorithm_t alg2; -}; -typedef struct psa_key_policy_s psa_key_policy_t; - -#define PSA_KEY_POLICY_INIT {0, 0, 0} -static inline struct psa_key_policy_s psa_key_policy_init( void ) -{ - const struct psa_key_policy_s v = PSA_KEY_POLICY_INIT; - return( v ); -} - -/* The type used internally for key sizes. - * Public interfaces use size_t, but internally we use a smaller type. */ -typedef uint16_t psa_key_bits_t; -/* The maximum value of the type used to represent bit-sizes. - * This is used to mark an invalid key size. */ -#define PSA_KEY_BITS_TOO_LARGE ( (psa_key_bits_t) ( -1 ) ) -/* The maximum size of a key in bits. - * Currently defined as the maximum that can be represented, rounded down - * to a whole number of bytes. - * This is an uncast value so that it can be used in preprocessor - * conditionals. */ -#define PSA_MAX_KEY_BITS 0xfff8 - -/** A mask of flags that can be stored in key attributes. - * - * This type is also used internally to store flags in slots. Internal - * flags are defined in library/psa_crypto_core.h. Internal flags may have - * the same value as external flags if they are properly handled during - * key creation and in psa_get_key_attributes. - */ -typedef uint16_t psa_key_attributes_flag_t; - -#define MBEDTLS_PSA_KA_FLAG_HAS_SLOT_NUMBER \ - ( (psa_key_attributes_flag_t) 0x0001 ) - -/* A mask of key attribute flags used externally only. - * Only meant for internal checks inside the library. */ -#define MBEDTLS_PSA_KA_MASK_EXTERNAL_ONLY ( \ - MBEDTLS_PSA_KA_FLAG_HAS_SLOT_NUMBER | \ - 0 ) - -/* A mask of key attribute flags used both internally and externally. - * Currently there aren't any. */ -#define MBEDTLS_PSA_KA_MASK_DUAL_USE ( \ - 0 ) - -typedef struct -{ - psa_key_type_t type; - psa_key_lifetime_t lifetime; - psa_key_id_t id; - psa_key_policy_t policy; - psa_key_bits_t bits; - psa_key_attributes_flag_t flags; -} psa_core_key_attributes_t; - -#define PSA_CORE_KEY_ATTRIBUTES_INIT {0, 0, PSA_KEY_ID_INIT, PSA_KEY_POLICY_INIT, 0, 0} - -struct psa_key_attributes_s -{ - psa_core_key_attributes_t core; -#if defined(MBEDTLS_PSA_CRYPTO_SE_C) - psa_key_slot_number_t slot_number; -#endif /* MBEDTLS_PSA_CRYPTO_SE_C */ - void *domain_parameters; - size_t domain_parameters_size; -}; - -#if defined(MBEDTLS_PSA_CRYPTO_SE_C) -#define PSA_KEY_ATTRIBUTES_INIT {PSA_CORE_KEY_ATTRIBUTES_INIT, 0, NULL, 0} -#else -#define PSA_KEY_ATTRIBUTES_INIT {PSA_CORE_KEY_ATTRIBUTES_INIT, NULL, 0} -#endif - -static inline struct psa_key_attributes_s psa_key_attributes_init( void ) -{ - const struct psa_key_attributes_s v = PSA_KEY_ATTRIBUTES_INIT; - return( v ); -} - -static inline void psa_set_key_id(psa_key_attributes_t *attributes, - psa_key_id_t id) -{ - attributes->core.id = id; - if( attributes->core.lifetime == PSA_KEY_LIFETIME_VOLATILE ) - attributes->core.lifetime = PSA_KEY_LIFETIME_PERSISTENT; -} - -static inline psa_key_id_t psa_get_key_id( - const psa_key_attributes_t *attributes) -{ - return( attributes->core.id ); -} - -static inline void psa_set_key_lifetime(psa_key_attributes_t *attributes, - psa_key_lifetime_t lifetime) -{ - attributes->core.lifetime = lifetime; - if( lifetime == PSA_KEY_LIFETIME_VOLATILE ) - { -#ifdef MBEDTLS_PSA_CRYPTO_KEY_FILE_ID_ENCODES_OWNER - attributes->core.id.key_id = 0; - attributes->core.id.owner = 0; -#else - attributes->core.id = 0; -#endif - } -} - -static inline psa_key_lifetime_t psa_get_key_lifetime( - const psa_key_attributes_t *attributes) -{ - return( attributes->core.lifetime ); -} - -static inline void psa_set_key_usage_flags(psa_key_attributes_t *attributes, - psa_key_usage_t usage_flags) -{ - attributes->core.policy.usage = usage_flags; -} - -static inline psa_key_usage_t psa_get_key_usage_flags( - const psa_key_attributes_t *attributes) -{ - return( attributes->core.policy.usage ); -} - -static inline void psa_set_key_algorithm(psa_key_attributes_t *attributes, - psa_algorithm_t alg) -{ - attributes->core.policy.alg = alg; -} - -static inline psa_algorithm_t psa_get_key_algorithm( - const psa_key_attributes_t *attributes) -{ - return( attributes->core.policy.alg ); -} - -/* This function is declared in crypto_extra.h, which comes after this - * header file, but we need the function here, so repeat the declaration. */ -psa_status_t psa_set_key_domain_parameters(psa_key_attributes_t *attributes, - psa_key_type_t type, - const uint8_t *data, - size_t data_length); - -static inline void psa_set_key_type(psa_key_attributes_t *attributes, - psa_key_type_t type) -{ - if( attributes->domain_parameters == NULL ) - { - /* Common case: quick path */ - attributes->core.type = type; - } - else - { - /* Call the bigger function to free the old domain paramteres. - * Ignore any errors which may arise due to type requiring - * non-default domain parameters, since this function can't - * report errors. */ - (void) psa_set_key_domain_parameters( attributes, type, NULL, 0 ); - } -} - -static inline psa_key_type_t psa_get_key_type( - const psa_key_attributes_t *attributes) -{ - return( attributes->core.type ); -} - -static inline void psa_set_key_bits(psa_key_attributes_t *attributes, - size_t bits) -{ - if( bits > PSA_MAX_KEY_BITS ) - attributes->core.bits = PSA_KEY_BITS_TOO_LARGE; - else - attributes->core.bits = (psa_key_bits_t) bits; -} - -static inline size_t psa_get_key_bits( - const psa_key_attributes_t *attributes) -{ - return( attributes->core.bits ); -} - -#ifdef __cplusplus -} -#endif - -#endif /* PSA_CRYPTO_STRUCT_H */ diff --git a/components/TARGET_PSA/services/crypto/COMPONENT_PSA_SRV_IPC/psa_crypto_spm.c b/components/TARGET_PSA/services/crypto/COMPONENT_PSA_SRV_IPC/psa_crypto_spm.c deleted file mode 100644 index c50004a..0000000 --- a/components/TARGET_PSA/services/crypto/COMPONENT_PSA_SRV_IPC/psa_crypto_spm.c +++ /dev/null @@ -1,1636 +0,0 @@ -/* - * PSA crypto layer on top of Mbed TLS crypto - */ -/* Copyright (C) 2018, ARM Limited, All Rights Reserved - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * This file is part of mbed TLS (https://tls.mbed.org) - */ - -#if !defined(MBEDTLS_CONFIG_FILE) -#include "mbedtls/config.h" -#else -#include MBEDTLS_CONFIG_FILE -#endif - -#if defined(MBEDTLS_PSA_CRYPTO_C) - -#include -#include -#include - -#include "psa_manifest/sid.h" -#include "psa/client.h" -#include "psa/crypto.h" -#include "crypto_platform_spe.h" -#include "mbed_assert.h" - -#define MINOR_VER 1 -#define CLIENT_PSA_KEY_ID_SIZE_IN_BYTES 4 - -MBED_STATIC_ASSERT(sizeof(psa_key_id_t) == CLIENT_PSA_KEY_ID_SIZE_IN_BYTES, "Unexpected psa_key_id_t size"); - -/****************************************************************/ -/* INTERNAL HELPER FUNCTIONS */ -/****************************************************************/ -static psa_status_t ipc_connect(uint32_t sid, psa_handle_t *handle) -{ - *handle = psa_connect(sid, MINOR_VER); - if (*handle <= PSA_NULL_HANDLE) { - return (PSA_ERROR_COMMUNICATION_FAILURE); - } - return (PSA_SUCCESS); -} - -static inline void ipc_close(psa_handle_t *handle) -{ - psa_close(*handle); - *handle = PSA_NULL_HANDLE; -} - -static psa_status_t ipc_call(psa_handle_t *handle, psa_invec *in_vec, size_t in_vec_size, - psa_outvec *out_vec, size_t out_vec_size, bool close) -{ - if (*handle <= PSA_NULL_HANDLE) { - return (PSA_ERROR_BAD_STATE); - } - - psa_status_t status = psa_call(*handle, in_vec, in_vec_size, out_vec, out_vec_size); - if (close) { - ipc_close(handle); - } - return (status); -} - -static psa_status_t ipc_oneshot(uint32_t sid, psa_invec *in_vec, size_t in_vec_size, - psa_outvec *out_vec, size_t out_vec_size) -{ - psa_handle_t handle = PSA_NULL_HANDLE; - psa_status_t status = ipc_connect(sid, &handle); - if (status != PSA_SUCCESS) { - return status; - } - status = ipc_call(&handle, in_vec, in_vec_size, out_vec, out_vec_size, true); - return (status); -} - - -/* - * PSA Crypto API (crypto.h) - */ - -psa_status_t psa_crypto_init(void) -{ - psa_status_t status = ipc_oneshot(PSA_CRYPTO_INIT_ID, NULL, 0, NULL, 0); - return (status); -} - -psa_status_t psa_get_key_attributes(psa_key_handle_t handle, - psa_key_attributes_t *attributes) -{ - psa_key_mng_ipc_t psa_key_mng_ipc = { - .func = PSA_GET_KEY_ATTRIBUTES, - .handle = handle - }; - - psa_invec in_vec = { &psa_key_mng_ipc, sizeof(psa_key_mng_ipc) }; - - psa_outvec out_vec = { attributes, sizeof(*attributes) }; - - return ipc_oneshot(PSA_KEY_MNG_ID, &in_vec, 1, &out_vec, 1); -} - -void psa_reset_key_attributes(psa_key_attributes_t *attributes) -{ - /* The reset of key attributes can happen entirely without going to the - * core. In fact, it can't go to the core without causing issues with - * memory ownership. Given that psa_set_key_domain_parameters(), which we - * currently don't allow in the client/server architecture, allocates - * memory that would be freed by psa_reset_key_attributes(), we must do - * this in the NSPE due to lack of memory ownership information in the - * core; the SPE can't currently know if any given allocation is valid to - * free for a given client. */ - - /* Note attributes->domain_parameters are currently ignored, as we don't - * currently support them in client/server architecture. */ - memset(attributes, 0, sizeof(*attributes)); -} - -psa_status_t psa_set_key_domain_parameters(psa_key_attributes_t *attributes, - psa_key_type_t type, - const uint8_t *data, - size_t data_length) -{ - return PSA_ERROR_NOT_SUPPORTED; -} - -psa_status_t psa_get_key_domain_parameters(const psa_key_attributes_t *attributes, - uint8_t *data, - size_t data_size, - size_t *data_length) -{ - return PSA_ERROR_NOT_SUPPORTED; -} - -psa_status_t psa_open_key(psa_key_id_t id, - psa_key_handle_t *handle) -{ - psa_key_mng_ipc_t psa_key_mng_ipc = { - .func = PSA_OPEN_KEY, - .handle = *handle, - }; - - psa_invec in_vec[2] = { - { &psa_key_mng_ipc, sizeof(psa_key_mng_ipc) }, - { &id, sizeof(id) } - }; - - psa_outvec out_vec = { handle, sizeof(*handle) }; - - psa_status_t status = ipc_oneshot(PSA_KEY_MNG_ID, in_vec, 2, &out_vec, 1); - return (status); -} - -psa_status_t psa_close_key(psa_key_handle_t handle) -{ - psa_key_mng_ipc_t psa_key_mng_ipc = { - .func = PSA_CLOSE_KEY, - .handle = handle, - }; - - psa_invec in_vec = { &psa_key_mng_ipc, sizeof(psa_key_mng_ipc) }; - - psa_status_t status = ipc_oneshot(PSA_KEY_MNG_ID, &in_vec, 1, NULL, 0); - return (status); -} - -psa_status_t psa_import_key(const psa_key_attributes_t *attributes, - const uint8_t *data, - size_t data_length, - psa_key_handle_t *handle) -{ - psa_key_mng_ipc_t psa_key_mng_ipc = { - .func = PSA_IMPORT_KEY, - .handle = 0, - }; - - psa_invec in_vec[3] = { - { &psa_key_mng_ipc, sizeof(psa_key_mng_ipc) }, - { attributes, sizeof(*attributes) }, - { data, data_length }, - }; - - psa_outvec out_vec = { handle, sizeof(*handle) }; - - return ipc_oneshot(PSA_KEY_MNG_ID, in_vec, 3, &out_vec, 1); -} - -psa_status_t psa_destroy_key(psa_key_handle_t handle) -{ - psa_key_mng_ipc_t psa_key_mng_ipc = { - .func = PSA_DESTROY_KEY, - .handle = handle, - }; - - psa_invec in_vec = { &psa_key_mng_ipc, sizeof(psa_key_mng_ipc) }; - - psa_status_t status = ipc_oneshot(PSA_KEY_MNG_ID, &in_vec, 1, NULL, 0); - return (status); -} - -static psa_status_t psa_export_key_common(psa_key_handle_t handle, - uint8_t *data, - size_t data_size, - size_t *data_length, - psa_sec_function_t func) -{ - psa_key_mng_ipc_t psa_key_mng_ipc = { - .func = func, - .handle = handle, - }; - - psa_invec in_vec = { &psa_key_mng_ipc, sizeof(psa_key_mng_ipc) }; - - psa_outvec out_vec[2] = { - { data, data_size }, - { data_length, sizeof(*data_length) } - }; - - psa_status_t status = ipc_oneshot(PSA_KEY_MNG_ID, &in_vec, 1, out_vec, 2); - return (status); -} - -psa_status_t psa_export_key(psa_key_handle_t handle, - uint8_t *data, - size_t data_size, - size_t *data_length) -{ - psa_status_t status = psa_export_key_common(handle, data, data_size, - data_length, PSA_EXPORT_KEY); - return (status); -} - -psa_status_t psa_export_public_key(psa_key_handle_t handle, - uint8_t *data, - size_t data_size, - size_t *data_length) -{ - psa_status_t status = psa_export_key_common(handle, data, data_size, - data_length, - PSA_EXPORT_PUBLIC_KEY); - return (status); -} - -psa_status_t psa_copy_key(psa_key_handle_t source_handle, - const psa_key_attributes_t *attributes, - psa_key_handle_t *target_handle) -{ - psa_key_mng_ipc_t psa_key_mng_ipc = { - .func = PSA_COPY_KEY, - .handle = source_handle, - }; - - psa_invec in_vec = { &psa_key_mng_ipc, sizeof(psa_key_mng_ipc) }; - - psa_outvec out_vec = { target_handle, sizeof(*target_handle) }; - - return ipc_oneshot(PSA_KEY_MNG_ID, &in_vec, 1, &out_vec, 1); -} - -psa_status_t psa_hash_compute(psa_algorithm_t alg, - const uint8_t *input, - size_t input_length, - uint8_t *hash, - size_t hash_size, - size_t *hash_length) -{ - psa_crypto_ipc_t psa_crypto_ipc = { - .func = PSA_HASH_COMPUTE, - .handle = 0, - .alg = alg, - }; - - psa_invec in_vec[2] = { - { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }, - { input, input_length } - }; - - psa_outvec out_vec[2] = { - { hash, hash_size }, - { hash_length, sizeof(*hash_length) } - }; - - return ipc_oneshot(PSA_HASH_ID, in_vec, 2, out_vec, 2); -} - -psa_status_t psa_hash_compare(psa_algorithm_t alg, - const uint8_t *input, - size_t input_length, - const uint8_t *hash, - const size_t hash_length) -{ - psa_crypto_ipc_t psa_crypto_ipc = { - .func = PSA_HASH_COMPARE, - .handle = 0, - .alg = alg, - }; - - psa_invec in_vec[3] = { - { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }, - { input, input_length }, - { hash, hash_length }, - }; - - return ipc_oneshot(PSA_HASH_ID, in_vec, 3, NULL, 0); -} - -psa_status_t psa_hash_setup(psa_hash_operation_t *operation, - psa_algorithm_t alg) -{ - if (operation->handle != PSA_NULL_HANDLE) { - return (PSA_ERROR_BAD_STATE); - } - - psa_crypto_ipc_t psa_crypto_ipc = { - .func = PSA_HASH_SETUP, - .handle = 0, - .alg = alg - }; - - psa_invec in_vec = { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }; - - psa_status_t status = ipc_connect(PSA_HASH_ID, &operation->handle); - if (status != PSA_SUCCESS) { - return (status); - } - status = ipc_call(&operation->handle, &in_vec, 1, NULL, 0, false); - if (status != PSA_SUCCESS) { - ipc_close(&operation->handle); - } - return (status); -} - -psa_status_t psa_hash_update(psa_hash_operation_t *operation, - const uint8_t *input, - size_t input_length) -{ - psa_crypto_ipc_t psa_crypto_ipc = { - .func = PSA_HASH_UPDATE, - .handle = 0, - .alg = 0 - }; - - psa_invec in_vec[2] = { - { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }, - { input, input_length } - }; - - psa_status_t status = ipc_call(&operation->handle, in_vec, 2, NULL, 0, false); - if (status != PSA_SUCCESS) { - ipc_close(&operation->handle); - } - return (status); -} - -psa_status_t psa_hash_finish(psa_hash_operation_t *operation, - uint8_t *hash, - size_t hash_size, - size_t *hash_length) -{ - psa_crypto_ipc_t psa_crypto_ipc = { - .func = PSA_HASH_FINISH, - .handle = 0, - .alg = 0 - }; - - psa_invec in_vec[2] = { - { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }, - { &hash_size, sizeof(hash_size) } - }; - - psa_outvec out_vec[2] = { - { hash, hash_size }, - { hash_length, sizeof(*hash_length) } - }; - - psa_status_t status = ipc_call(&operation->handle, in_vec, 2, out_vec, 2, true); - return (status); -} - -psa_status_t psa_hash_verify(psa_hash_operation_t *operation, - const uint8_t *hash, - size_t hash_length) -{ - psa_crypto_ipc_t psa_crypto_ipc = { - .func = PSA_HASH_VERIFY, - .handle = 0, - .alg = 0 - }; - - psa_invec in_vec[3] = { - { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }, - { &hash_length, sizeof(hash_length) }, - { hash, hash_length } - }; - - psa_status_t status = ipc_call(&operation->handle, in_vec, 3, NULL, 0, true); - return (status); -} - -psa_status_t psa_hash_abort(psa_hash_operation_t *operation) -{ - if (operation->handle <= PSA_NULL_HANDLE) { - return (PSA_SUCCESS); - } - - psa_crypto_ipc_t psa_crypto_ipc = { - .func = PSA_HASH_ABORT, - .handle = 0, - .alg = 0 - }; - - psa_invec in_vec = { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }; - - psa_status_t status = ipc_call(&operation->handle, &in_vec, 1, NULL, 0, true); - return (status); -} - -psa_status_t psa_hash_clone(const psa_hash_operation_t *source_operation, - psa_hash_operation_t *target_operation) -{ - if (source_operation->handle <= PSA_NULL_HANDLE || target_operation->handle != PSA_NULL_HANDLE) { - return (PSA_ERROR_BAD_STATE); - } - - psa_crypto_ipc_t psa_crypto_ipc = { - .func = 0, - .handle = 0, - .alg = 0 - }; - - size_t index = 0; - - psa_invec in_vec[2] = { - { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }, - { &index, sizeof(index) } - }; - - psa_outvec out_vec = { &index, sizeof(index) }; - - psa_status_t status = ipc_connect(PSA_HASH_ID, &target_operation->handle); - if (status != PSA_SUCCESS) { - return (status); - } - - psa_crypto_ipc.func = PSA_HASH_CLONE_BEGIN; - status = ipc_call((psa_handle_t *)&source_operation->handle, in_vec, 1, &out_vec, 1, false); - if (status != PSA_SUCCESS) { - goto exit; - } - - psa_crypto_ipc.func = PSA_HASH_CLONE_END; - status = ipc_call(&target_operation->handle, in_vec, 2, NULL, 0, false); - -exit: - if (status != PSA_SUCCESS) { - ipc_close(&target_operation->handle); - } - return (status); -} - -psa_status_t psa_mac_compute(psa_key_handle_t handle, - psa_algorithm_t alg, - const uint8_t *input, - size_t input_length, - uint8_t *mac, - size_t mac_size, - size_t *mac_length) -{ - psa_crypto_ipc_t psa_crypto_ipc = { - .func = PSA_MAC_COMPUTE, - .handle = handle, - .alg = alg, - }; - - psa_invec in_vec[2] = { - { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }, - { input, input_length }, - }; - - psa_outvec out_vec[2] = { - { mac, mac_size }, - { mac_length, sizeof(*mac_length) }, - }; - - psa_status_t status = ipc_oneshot(PSA_MAC_ID, in_vec, 2, out_vec, 2); - return (status); -} - -psa_status_t psa_mac_verify(psa_key_handle_t handle, - psa_algorithm_t alg, - const uint8_t *input, - size_t input_length, - const uint8_t *mac, - const size_t mac_length) -{ - psa_crypto_ipc_t psa_crypto_ipc = { - .func = PSA_MAC_VERIFY, - .handle = handle, - .alg = alg, - }; - - psa_invec in_vec[3] = { - { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }, - { input, input_length }, - { mac, mac_length }, - }; - - psa_status_t status = ipc_oneshot(PSA_MAC_ID, in_vec, 2, NULL, 0); - return (status); -} - -static psa_status_t psa_mac_setup(psa_mac_operation_t *operation, - psa_key_handle_t handle, - psa_algorithm_t alg, - psa_sec_function_t func) -{ - if (operation->handle != PSA_NULL_HANDLE) { - return (PSA_ERROR_BAD_STATE); - } - - psa_crypto_ipc_t psa_crypto_ipc = { - .func = func, - .handle = handle, - .alg = alg - }; - - psa_invec in_vec = { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }; - - psa_status_t status = ipc_connect(PSA_MAC_ID, &operation->handle); - if (status != PSA_SUCCESS) { - return (status); - } - status = ipc_call(&operation->handle, &in_vec, 1, NULL, 0, false); - if (status != PSA_SUCCESS) { - ipc_close(&operation->handle); - } - return (status); -} - -psa_status_t psa_mac_sign_setup(psa_mac_operation_t *operation, - psa_key_handle_t handle, - psa_algorithm_t alg) -{ - psa_status_t status = psa_mac_setup(operation, handle, alg, PSA_MAC_SIGN_SETUP); - return (status); -} - -psa_status_t psa_mac_verify_setup(psa_mac_operation_t *operation, - psa_key_handle_t handle, - psa_algorithm_t alg) -{ - psa_status_t status = psa_mac_setup(operation, handle, alg, PSA_MAC_VERIFY_SETUP); - return (status); -} - -psa_status_t psa_mac_update(psa_mac_operation_t *operation, - const uint8_t *input, - size_t input_length) -{ - psa_crypto_ipc_t psa_crypto_ipc = { - .func = PSA_MAC_UPDATE, - .handle = 0, - .alg = 0 - }; - - psa_invec in_vec[2] = { - { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }, - { input, input_length } - }; - - psa_status_t status = ipc_call(&operation->handle, in_vec, 2, NULL, 0, false); - if (status != PSA_SUCCESS) { - ipc_close(&operation->handle); - } - return (status); -} - -psa_status_t psa_mac_sign_finish(psa_mac_operation_t *operation, - uint8_t *mac, - size_t mac_size, - size_t *mac_length) -{ - psa_crypto_ipc_t psa_crypto_ipc = { - .func = PSA_MAC_SIGN_FINISH, - .handle = 0, - .alg = 0 - }; - - psa_invec in_vec[2] = { - { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }, - { &mac_size, sizeof(mac_size) } - }; - - psa_outvec out_vec[2] = { - { mac, mac_size }, - { mac_length, sizeof(*mac_length) } - }; - - psa_status_t status = ipc_call(&operation->handle, in_vec, 2, out_vec, 2, true); - return (status); -} - -psa_status_t psa_mac_verify_finish(psa_mac_operation_t *operation, - const uint8_t *mac, - size_t mac_length) -{ - psa_crypto_ipc_t psa_crypto_ipc = { - .func = PSA_MAC_VERIFY_FINISH, - .handle = 0, - .alg = 0 - }; - - psa_invec in_vec[3] = { - { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }, - { &mac_length, sizeof(mac_length) }, - { mac, mac_length } - }; - - psa_status_t status = ipc_call(&operation->handle, in_vec, 3, NULL, 0, true); - return (status); -} - -psa_status_t psa_mac_abort(psa_mac_operation_t *operation) -{ - if (operation->handle <= PSA_NULL_HANDLE) { - return (PSA_SUCCESS); - } - - psa_crypto_ipc_t psa_crypto_ipc = { - .func = PSA_MAC_ABORT, - .handle = 0, - .alg = 0 - }; - - psa_invec in_vec = { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }; - - psa_status_t status = ipc_call(&operation->handle, &in_vec, 1, NULL, 0, true); - return (status); -} - -psa_status_t psa_cipher_encrypt(psa_key_handle_t handle, - psa_algorithm_t alg, - const uint8_t *input, - size_t input_length, - uint8_t *output, - size_t output_size, - size_t *output_length) -{ - psa_crypto_ipc_t psa_crypto_ipc = { - .func = PSA_CIPHER_ENCRYPT, - .handle = handle, - .alg = alg, - }; - - psa_invec in_vec[2] = { - { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }, - { input, input_length }, - }; - - psa_outvec out_vec[2] = { - { output, output_size }, - { output_length, sizeof(*output_length) }, - }; - - psa_status_t status = ipc_oneshot(PSA_SYMMETRIC_ID, in_vec, 2, out_vec, 2); - return (status); -} - -psa_status_t psa_cipher_decrypt(psa_key_handle_t handle, - psa_algorithm_t alg, - const uint8_t *input, - size_t input_length, - uint8_t *output, - size_t output_size, - size_t *output_length) -{ - psa_crypto_ipc_t psa_crypto_ipc = { - .func = PSA_CIPHER_DECRYPT, - .handle = handle, - .alg = alg, - }; - - psa_invec in_vec[3] = { - { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }, - { input, input_length }, - }; - - psa_outvec out_vec[2] = { - { output, output_size }, - { output_length, sizeof(*output_length) }, - }; - - psa_status_t status = ipc_oneshot(PSA_SYMMETRIC_ID, in_vec, 2, out_vec, 2); - return (status); -} - -static psa_status_t psa_cipher_setup(psa_cipher_operation_t *operation, - psa_key_handle_t handle, - psa_algorithm_t alg, - psa_sec_function_t func) -{ - if (operation->handle != PSA_NULL_HANDLE) { - return (PSA_ERROR_BAD_STATE); - } - - psa_crypto_ipc_t psa_crypto_ipc = { - .func = func, - .handle = handle, - .alg = alg - }; - - psa_invec in_vec = { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }; - - psa_status_t status = ipc_connect(PSA_SYMMETRIC_ID, &operation->handle); - if (status != PSA_SUCCESS) { - return (status); - } - status = ipc_call(&operation->handle, &in_vec, 1, NULL, 0, false); - if (status != PSA_SUCCESS) { - ipc_close(&operation->handle); - } - return (status); -} - -psa_status_t psa_cipher_encrypt_setup(psa_cipher_operation_t *operation, - psa_key_handle_t handle, - psa_algorithm_t alg) -{ - psa_status_t status = psa_cipher_setup(operation, handle, alg, PSA_CIPHER_ENCRYPT_SETUP); - return (status); -} - -psa_status_t psa_cipher_decrypt_setup(psa_cipher_operation_t *operation, - psa_key_handle_t handle, - psa_algorithm_t alg) -{ - psa_status_t status = psa_cipher_setup(operation, handle, alg, PSA_CIPHER_DECRYPT_SETUP); - return (status); -} - -psa_status_t psa_cipher_generate_iv(psa_cipher_operation_t *operation, - uint8_t *iv, - size_t iv_size, - size_t *iv_length) -{ - psa_crypto_ipc_t psa_crypto_ipc = { - .func = PSA_CIPHER_GENERATE_IV, - .handle = 0, - .alg = 0 - }; - - psa_invec in_vec = { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }; - - psa_outvec out_vec[2] = { - { iv, iv_size }, - { iv_length, sizeof(*iv_length) } - }; - - psa_status_t status = ipc_call(&operation->handle, &in_vec, 1, out_vec, 2, false); - if (status != PSA_SUCCESS) { - ipc_close(&operation->handle); - } - return (status); -} - -psa_status_t psa_cipher_set_iv(psa_cipher_operation_t *operation, - const uint8_t *iv, - size_t iv_length) -{ - psa_crypto_ipc_t psa_crypto_ipc = { - .func = PSA_CIPHER_SET_IV, - .handle = 0, - .alg = 0 - }; - - psa_invec in_vec[2] = { - { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }, - { iv, iv_length } - }; - - psa_status_t status = ipc_call(&operation->handle, in_vec, 2, NULL, 0, false); - if (status != PSA_SUCCESS) { - ipc_close(&operation->handle); - } - return (status); -} - -psa_status_t psa_cipher_update(psa_cipher_operation_t *operation, - const uint8_t *input, - size_t input_length, - uint8_t *output, - size_t output_size, - size_t *output_length) -{ - psa_crypto_ipc_t psa_crypto_ipc = { - .func = PSA_CIPHER_UPDATE, - .handle = 0, - .alg = 0 - }; - - psa_invec in_vec[2] = { - { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }, - { input, input_length } - }; - - psa_outvec out_vec[2] = { - { output, output_size }, - { output_length, (output_length == NULL ? 0 : sizeof(*output_length)) } - }; - - psa_status_t status = ipc_call(&operation->handle, in_vec, 2, out_vec, 2, false); - if (status != PSA_SUCCESS) { - ipc_close(&operation->handle); - } - return (status); -} - -psa_status_t psa_cipher_finish(psa_cipher_operation_t *operation, - uint8_t *output, - size_t output_size, - size_t *output_length) -{ - psa_crypto_ipc_t psa_crypto_ipc = { - .func = PSA_CIPHER_FINISH, - .handle = 0, - .alg = 0 - }; - - psa_invec in_vec = { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }; - - psa_outvec out_vec[2] = { - { output, output_size }, - { output_length, (output_length == NULL ? 0 : sizeof(*output_length)) } - }; - - psa_status_t status = ipc_call(&operation->handle, &in_vec, 1, out_vec, 2, true); - return (status); -} - -psa_status_t psa_cipher_abort(psa_cipher_operation_t *operation) -{ - if (operation->handle <= PSA_NULL_HANDLE) { - return (PSA_SUCCESS); - } - - psa_crypto_ipc_t psa_crypto_ipc = { - .func = PSA_CIPHER_ABORT, - .handle = 0, - .alg = 0 - }; - - psa_invec in_vec = { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }; - - psa_status_t status = ipc_call(&operation->handle, &in_vec, 1, NULL, 0, true); - return (status); -} - -psa_status_t psa_aead_encrypt(psa_key_handle_t handle, - psa_algorithm_t alg, - const uint8_t *nonce, - size_t nonce_length, - const uint8_t *additional_data, - size_t additional_data_length, - const uint8_t *plaintext, - size_t plaintext_length, - uint8_t *ciphertext, - size_t ciphertext_size, - size_t *ciphertext_length) -{ - if (nonce_length > PSA_AEAD_MAX_NONCE_SIZE) { - return (PSA_ERROR_INVALID_ARGUMENT); - } - - uint8_t *buffer = calloc(1, (additional_data_length + plaintext_length)); - if (buffer == NULL) { - return (PSA_ERROR_INSUFFICIENT_MEMORY); - } - - psa_crypto_ipc_aead_t psa_crypto_ipc = { - .func = PSA_AEAD_ENCRYPT, - .handle = handle, - .alg = alg, - .nonce_size = nonce_length, - .additional_data_length = additional_data_length, - .input_length = plaintext_length, - .nonce = { 0 } - }; - - psa_invec in_vec[2] = { - { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }, - { buffer, (additional_data_length + plaintext_length) } - }; - - psa_outvec out_vec[2] = { - { ciphertext, ciphertext_size }, - { ciphertext_length, sizeof(*ciphertext_length) } - }; - - psa_status_t status; - memcpy(buffer, additional_data, additional_data_length); - memcpy(buffer + additional_data_length, plaintext, plaintext_length); - memcpy(psa_crypto_ipc.nonce, nonce, nonce_length); - - status = ipc_oneshot(PSA_AEAD_ID, in_vec, 2, out_vec, 2); - free(buffer); - return (status); -} - -psa_status_t psa_aead_decrypt(psa_key_handle_t handle, - psa_algorithm_t alg, - const uint8_t *nonce, - size_t nonce_length, - const uint8_t *additional_data, - size_t additional_data_length, - const uint8_t *ciphertext, - size_t ciphertext_length, - uint8_t *plaintext, - size_t plaintext_size, - size_t *plaintext_length) -{ - if (nonce_length > PSA_AEAD_MAX_NONCE_SIZE) { - return (PSA_ERROR_INVALID_ARGUMENT); - } - - uint8_t *buffer = calloc(1, (additional_data_length + ciphertext_length)); - if (buffer == NULL) { - return (PSA_ERROR_INSUFFICIENT_MEMORY); - } - - psa_crypto_ipc_aead_t psa_crypto_ipc = { - .func = PSA_AEAD_DECRYPT, - .handle = handle, - .alg = alg, - .nonce_size = nonce_length, - .additional_data_length = additional_data_length, - .input_length = ciphertext_length, - .nonce = { 0 } - }; - - psa_invec in_vec[2] = { - { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }, - { buffer, (additional_data_length + ciphertext_length) } - }; - - psa_outvec out_vec[2] = { - { plaintext, plaintext_size }, - { plaintext_length, sizeof(*plaintext_length) } - }; - - psa_status_t status; - memcpy(buffer, additional_data, additional_data_length); - memcpy(buffer + additional_data_length, ciphertext, ciphertext_length); - memcpy(psa_crypto_ipc.nonce, nonce, nonce_length); - - status = ipc_oneshot(PSA_AEAD_ID, in_vec, 2, out_vec, 2); - free(buffer); - return (status); -} - -static psa_status_t psa_aead_setup(psa_aead_operation_t *operation, - psa_key_handle_t handle, - psa_algorithm_t alg, - psa_sec_function_t func) -{ - if (operation->handle != PSA_NULL_HANDLE) { - return PSA_ERROR_BAD_STATE; - } - - psa_crypto_ipc_t psa_crypto_ipc = { - .func = func, - .handle = handle, - .alg = alg - }; - - psa_invec in_vec = { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }; - - psa_status_t status = ipc_connect(PSA_AEAD_ID, &operation->handle); - if (status != PSA_SUCCESS) { - return status; - } - status = ipc_call(&operation->handle, &in_vec, 1, NULL, 0, false); - if (status != PSA_SUCCESS) { - ipc_close(&operation->handle); - } - return status; -} - -psa_status_t psa_aead_encrypt_setup(psa_aead_operation_t *operation, - psa_key_handle_t handle, - psa_algorithm_t alg) -{ - return psa_aead_setup(operation, handle, alg, PSA_AEAD_ENCRYPT_SETUP); -} - -psa_status_t psa_aead_decrypt_setup(psa_aead_operation_t *operation, - psa_key_handle_t handle, - psa_algorithm_t alg) -{ - return psa_aead_setup(operation, handle, alg, PSA_AEAD_DECRYPT_SETUP); -} - -psa_status_t psa_aead_generate_nonce(psa_aead_operation_t *operation, - uint8_t *nonce, - size_t nonce_size, - size_t *nonce_length) -{ - if (operation->handle <= PSA_NULL_HANDLE) { - return PSA_ERROR_BAD_STATE; - } - - psa_crypto_ipc_aead_t psa_crypto_ipc = { - .func = PSA_AEAD_GENERATE_NONCE, - .handle = 0, - }; - - psa_invec in_vec[1] = { - { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }, - }; - - psa_outvec out_vec[2] = { - { nonce, nonce_size }, - { nonce_length, sizeof(*nonce_length) }, - }; - - return ipc_call(&operation->handle, in_vec, 1, out_vec, 2, false); -} - -psa_status_t psa_aead_set_nonce(psa_aead_operation_t *operation, - const uint8_t *nonce, - size_t nonce_length) -{ - if (operation->handle <= PSA_NULL_HANDLE) { - return PSA_ERROR_BAD_STATE; - } - - if (nonce_length > PSA_AEAD_MAX_NONCE_SIZE) { - return (PSA_ERROR_INVALID_ARGUMENT); - } - - psa_crypto_ipc_aead_t psa_crypto_ipc = { - .func = PSA_AEAD_SET_NONCE, - .handle = 0, - }; - - psa_invec in_vec[2] = { - { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }, - { nonce, nonce_length } - }; - - return ipc_call(&operation->handle, in_vec, 2, NULL, 0, false); -} - -psa_status_t psa_aead_set_lengths(psa_aead_operation_t *operation, - size_t ad_length, - size_t plaintext_length) -{ - if (operation->handle <= PSA_NULL_HANDLE) { - return PSA_ERROR_BAD_STATE; - } - - psa_crypto_ipc_aead_t psa_crypto_ipc = { - .func = PSA_AEAD_SET_LENGTHS, - .handle = 0, - .alg = 0, - .additional_data_length = ad_length, - .input_length = plaintext_length, - }; - - psa_invec in_vec[1] = { - { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }, - }; - - return ipc_call(&operation->handle, in_vec, 1, NULL, 0, false); -} - -psa_status_t psa_aead_update_ad(psa_aead_operation_t *operation, - const uint8_t *input, - size_t input_length) -{ - if (operation->handle <= PSA_NULL_HANDLE) { - return PSA_ERROR_BAD_STATE; - } - - psa_crypto_ipc_aead_t psa_crypto_ipc = { - .func = PSA_AEAD_UPDATE_AD, - .handle = 0, - .alg = 0, - }; - - psa_invec in_vec[2] = { - { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }, - { input, input_length }, - }; - - return ipc_call(&operation->handle, in_vec, 2, NULL, 0, false); -} - -psa_status_t psa_aead_update(psa_aead_operation_t *operation, - const uint8_t *input, - size_t input_length, - uint8_t *output, - size_t output_size, - size_t *output_length) -{ - if (operation->handle <= PSA_NULL_HANDLE) { - return PSA_ERROR_BAD_STATE; - } - - psa_crypto_ipc_aead_t psa_crypto_ipc = { - .func = PSA_AEAD_UPDATE, - .handle = 0, - .alg = 0, - }; - - psa_invec in_vec[2] = { - { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }, - { input, input_length }, - }; - - psa_outvec out_vec[2] = { - { output, output_size }, - { output_length, sizeof(*output_length) }, - }; - - return ipc_call(&operation->handle, in_vec, 2, out_vec, 2, false); -} - -psa_status_t psa_aead_finish(psa_aead_operation_t *operation, - uint8_t *ciphertext, - size_t ciphertext_size, - size_t *ciphertext_length, - uint8_t *tag, - size_t tag_size, - size_t *tag_length) -{ - if (operation->handle <= PSA_NULL_HANDLE) { - return PSA_ERROR_BAD_STATE; - } - - psa_crypto_ipc_t psa_crypto_ipc = { - .func = PSA_AEAD_FINISH, - .handle = 0, - .alg = 0 - }; - - psa_invec in_vec[1] = { - { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }, - }; - - psa_outvec out_vec[4] = { - { ciphertext, ciphertext_size }, - { ciphertext_length, (ciphertext_length == NULL ? 0 : sizeof(*ciphertext_length)) }, - { tag, tag_size }, - { tag_length, (tag_length == NULL ? 0 : sizeof(*tag_length)) }, - }; - - return ipc_call(&operation->handle, in_vec, 1, out_vec, 4, true); -} - -psa_status_t psa_aead_verify(psa_aead_operation_t *operation, - uint8_t *plaintext, - size_t plaintext_size, - size_t *plaintext_length, - const uint8_t *tag, - size_t tag_length) -{ - if (operation->handle <= PSA_NULL_HANDLE) { - return PSA_ERROR_BAD_STATE; - } - - psa_crypto_ipc_t psa_crypto_ipc = { - .func = PSA_AEAD_VERIFY, - .handle = 0, - .alg = 0 - }; - - psa_invec in_vec[3] = { - { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }, - { tag, tag_length }, - }; - - psa_outvec out_vec[2] = { - { plaintext, plaintext_size }, - { plaintext_length, (plaintext_length == NULL ? 0 : sizeof(*plaintext_length)) }, - }; - - return ipc_call(&operation->handle, in_vec, 3, out_vec, 2, true); -} - -psa_status_t psa_aead_abort(psa_aead_operation_t *operation) -{ - if (operation->handle <= PSA_NULL_HANDLE) { - return PSA_SUCCESS; - } - - psa_crypto_ipc_aead_t psa_crypto_ipc = { - .func = PSA_AEAD_ABORT, - .handle = 0, - .alg = 0 - }; - - psa_invec in_vec = { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }; - - return ipc_call(&operation->handle, &in_vec, 1, NULL, 0, true); -} - -psa_status_t psa_sign_hash(psa_key_handle_t handle, - psa_algorithm_t alg, - const uint8_t *hash, - size_t hash_length, - uint8_t *signature, - size_t signature_size, - size_t *signature_length) -{ - psa_crypto_ipc_asymmetric_t psa_crypto_ipc = { - .func = PSA_SIGN_HASH, - .handle = handle, - .alg = alg, - .input_length = 0, - .salt_length = 0 - }; - - psa_invec in_vec[2] = { - { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }, - { hash, hash_length } - }; - - psa_outvec out_vec[2] = { - { signature, signature_size }, - { signature_length, sizeof(*signature_length) } - }; - - psa_status_t status = ipc_oneshot(PSA_ASYMMETRIC_ID, in_vec, 2, out_vec, 2); - return (status); -} - -psa_status_t psa_verify_hash(psa_key_handle_t handle, - psa_algorithm_t alg, - const uint8_t *hash, - size_t hash_length, - const uint8_t *signature, - size_t signature_size) -{ - psa_crypto_ipc_asymmetric_t psa_crypto_ipc = { - .func = PSA_VERIFY_HASH, - .handle = handle, - .alg = alg, - .input_length = 0, - .salt_length = 0 - }; - - psa_invec in_vec[3] = { - { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }, - { signature, signature_size }, - { hash, hash_length } - }; - - psa_status_t status = ipc_oneshot(PSA_ASYMMETRIC_ID, in_vec, 3, NULL, 0); - return (status); -} - -static psa_status_t psa_asymmetric_operation(psa_sec_function_t func, - psa_key_handle_t handle, - psa_algorithm_t alg, - const uint8_t *input, - size_t input_length, - const uint8_t *salt, - size_t salt_length, - uint8_t *output, - size_t output_size, - size_t *output_length) -{ - uint8_t *buffer = calloc(1, (input_length + salt_length)); - if (buffer == NULL) { - return (PSA_ERROR_INSUFFICIENT_MEMORY); - } - - psa_crypto_ipc_asymmetric_t psa_crypto_ipc = { - .func = func, - .handle = handle, - .alg = alg, - .input_length = input_length, - .salt_length = salt_length - }; - - psa_invec in_vec[2] = { - { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }, - { buffer, (input_length + salt_length) } - }; - - psa_outvec out_vec[2] = { - { output, output_size }, - { output_length, sizeof(*output_length) } - }; - - psa_status_t status; - memcpy(buffer, input, input_length); - memcpy(buffer + input_length, salt, salt_length); - - status = ipc_oneshot(PSA_ASYMMETRIC_ID, in_vec, 2, out_vec, 2); - free(buffer); - return (status); -} - -psa_status_t psa_asymmetric_encrypt(psa_key_handle_t handle, - psa_algorithm_t alg, - const uint8_t *input, - size_t input_length, - const uint8_t *salt, - size_t salt_length, - uint8_t *output, - size_t output_size, - size_t *output_length) -{ - psa_status_t status = psa_asymmetric_operation(PSA_ASYMMETRIC_ENCRYPT, - handle, - alg, input, input_length, - salt, salt_length, output, - output_size, output_length); - return (status); -} - -psa_status_t psa_asymmetric_decrypt(psa_key_handle_t handle, - psa_algorithm_t alg, - const uint8_t *input, - size_t input_length, - const uint8_t *salt, - size_t salt_length, - uint8_t *output, - size_t output_size, - size_t *output_length) -{ - psa_status_t status = psa_asymmetric_operation(PSA_ASYMMETRIC_DECRYPT, - handle, - alg, input, input_length, - salt, salt_length, output, - output_size, output_length); - return (status); -} - -psa_status_t psa_key_derivation_setup( - psa_key_derivation_operation_t *operation, - psa_algorithm_t alg) -{ - if (operation->handle != PSA_NULL_HANDLE) { - return PSA_ERROR_BAD_STATE; - } - - psa_crypto_derivation_ipc_t psa_crypto_ipc = { - .func = PSA_KEY_DERIVATION_SETUP, - .handle = 0, - .alg = alg - }; - - psa_invec in_vec = { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }; - - psa_status_t status = ipc_connect(PSA_KEY_DERIVATION_ID, &operation->handle); - if (status != PSA_SUCCESS) { - return status; - } - - status = ipc_call(&operation->handle, &in_vec, 1, NULL, 0, false); - if (status != PSA_SUCCESS) { - ipc_close(&operation->handle); - } - - return status; -} - -psa_status_t psa_key_derivation_get_capacity( - const psa_key_derivation_operation_t *op, - size_t *capacity) -{ - psa_key_derivation_operation_t *operation = (psa_key_derivation_operation_t *) op; - - if (operation->handle <= PSA_NULL_HANDLE) { - return PSA_ERROR_BAD_STATE; - } - - psa_crypto_derivation_ipc_t psa_crypto_ipc = { - .func = PSA_KEY_DERIVATION_GET_CAPACITY, - .handle = 0, - .alg = 0, - }; - - psa_invec in_vec = { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }; - - psa_outvec out_vec = { capacity, sizeof(*capacity) }; - - return ipc_call(&operation->handle, &in_vec, 1, &out_vec, 1, false); -} - -psa_status_t psa_key_derivation_set_capacity( - psa_key_derivation_operation_t *operation, - size_t capacity) -{ - if (operation->handle <= PSA_NULL_HANDLE) { - return PSA_ERROR_BAD_STATE; - } - - psa_crypto_derivation_ipc_t psa_crypto_ipc = { - .func = PSA_KEY_DERIVATION_SET_CAPACITY, - .handle = 0, - .alg = 0, - }; - - psa_invec in_vec[2] = { - { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }, - { &capacity, sizeof(capacity) }, - }; - - return ipc_call(&operation->handle, in_vec, 2, NULL, 0, false); -} - -psa_status_t psa_key_derivation_input_bytes( - psa_key_derivation_operation_t *operation, - psa_key_derivation_step_t step, - const uint8_t *data, - size_t data_length) -{ - if (operation->handle <= PSA_NULL_HANDLE) { - return PSA_ERROR_BAD_STATE; - } - - psa_crypto_derivation_ipc_t psa_crypto_ipc = { - .func = PSA_KEY_DERIVATION_INPUT_BYTES, - .handle = 0, - .alg = 0, - }; - - psa_invec in_vec[3] = { - { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }, - { &step, sizeof(step) }, - { data, data_length }, - }; - - return ipc_call(&operation->handle, in_vec, 3, NULL, 0, false); -} - -psa_status_t psa_key_derivation_input_key( - psa_key_derivation_operation_t *operation, - psa_key_derivation_step_t step, - psa_key_handle_t handle) -{ - if (operation->handle <= PSA_NULL_HANDLE) { - return PSA_ERROR_BAD_STATE; - } - - psa_crypto_derivation_ipc_t psa_crypto_ipc = { - .func = PSA_KEY_DERIVATION_INPUT_KEY, - .handle = handle, - .alg = 0 - }; - - psa_invec in_vec[2] = { - { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }, - { &step, sizeof(step) }, - }; - - psa_status_t status = ipc_call(&operation->handle, in_vec, 2, NULL, 0, false); - return (status); -} - -psa_status_t psa_key_derivation_key_agreement( - psa_key_derivation_operation_t *operation, - psa_key_derivation_step_t step, - psa_key_handle_t private_key, - const uint8_t *peer_key, - size_t peer_key_length) -{ - if (operation->handle <= PSA_NULL_HANDLE) { - return PSA_ERROR_BAD_STATE; - } - - psa_crypto_derivation_ipc_t psa_crypto_ipc = { - .func = PSA_KEY_DERIVATION_KEY_AGREEMENT, - .handle = private_key, - .alg = 0, - }; - - psa_invec in_vec[3] = { - { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }, - { &step, sizeof(step) }, - { peer_key, peer_key_length }, - }; - - return ipc_call(&operation->handle, in_vec, 3, NULL, 0, false); -} - -psa_status_t psa_key_derivation_output_bytes( - psa_key_derivation_operation_t *operation, - uint8_t *output, - size_t output_length) -{ - if (operation->handle <= PSA_NULL_HANDLE) { - return PSA_ERROR_BAD_STATE; - } - - psa_crypto_derivation_ipc_t psa_crypto_ipc = { - .func = PSA_KEY_DERIVATION_OUTPUT_BYTES, - .handle = 0, - }; - - psa_invec in_vec = { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }; - - psa_outvec out_vec = { output, output_length }; - - return ipc_call(&operation->handle, &in_vec, 1, &out_vec, 1, false); -} - -psa_status_t psa_key_derivation_output_key( - const psa_key_attributes_t *attributes, - psa_key_derivation_operation_t *operation, - psa_key_handle_t *handle) -{ - if (operation->handle <= PSA_NULL_HANDLE) { - return PSA_ERROR_BAD_STATE; - } - - psa_crypto_derivation_ipc_t psa_crypto_ipc = { - .func = PSA_KEY_DERIVATION_OUTPUT_KEY, - }; - - psa_invec in_vec[2] = { - { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }, - { attributes, sizeof(*attributes) }, - }; - - psa_outvec out_vec = { handle, sizeof(*handle) }; - - return ipc_call(&operation->handle, in_vec, 2, &out_vec, 1, false); -} - -psa_status_t psa_key_derivation_abort( - psa_key_derivation_operation_t *operation) -{ - if (operation->handle <= PSA_NULL_HANDLE) { - return PSA_SUCCESS; - } - - psa_crypto_derivation_ipc_t psa_crypto_ipc = { - .func = PSA_KEY_DERIVATION_ABORT, - .handle = 0, - .alg = 0, - }; - - psa_invec in_vec = { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }; - - return ipc_call(&operation->handle, &in_vec, 1, NULL, 0, true); -} - -psa_status_t psa_raw_key_agreement(psa_algorithm_t alg, - psa_key_handle_t private_key, - const uint8_t *peer_key, - size_t peer_key_length, - uint8_t *output, - size_t output_size, - size_t *output_length) -{ - psa_crypto_derivation_ipc_t psa_crypto_ipc = { - .func = PSA_RAW_KEY_AGREEMENT, - .handle = private_key, - .alg = alg, - }; - - psa_invec in_vec[2] = { - { &psa_crypto_ipc, sizeof(psa_crypto_ipc) }, - { peer_key, peer_key_length }, - }; - - psa_outvec out_vec[2] = { - { output, output_size }, - { output_length, sizeof(*output_length) } - }; - - return ipc_oneshot(PSA_KEY_DERIVATION_ID, in_vec, 2, out_vec, 2); -} - -psa_status_t psa_generate_random(uint8_t *output, - size_t output_size) -{ - psa_outvec out_vec = { output, output_size }; - - psa_status_t status = ipc_oneshot(PSA_RNG_ID, NULL, 0, &out_vec, 1); - return (status); -} - -psa_status_t psa_generate_key(const psa_key_attributes_t *attributes, - psa_key_handle_t *handle) -{ - psa_key_mng_ipc_t psa_key_mng_ipc = { - .func = PSA_GENERATE_KEY, - }; - - psa_invec in_vec[2] = { - { &psa_key_mng_ipc, sizeof(psa_key_mng_ipc) }, - { attributes, sizeof(*attributes) }, - }; - - psa_outvec out_vec = { handle, sizeof(*handle) }; - - return ipc_oneshot(PSA_KEY_MNG_ID, in_vec, 2, &out_vec, 1); -} - - -/* - * PSA Crypto API extensions (crypto_extra.h) - */ - -void mbedtls_psa_crypto_free(void) -{ - ipc_oneshot(PSA_CRYPTO_FREE_ID, NULL, 0, NULL, 0); -} - -psa_status_t mbedtls_psa_inject_entropy(const uint8_t *seed, - size_t seed_size) -{ - psa_invec in_vec = { seed, seed_size }; - - psa_status_t status = ipc_oneshot(PSA_ENTROPY_ID, &in_vec, 1, NULL, 0); - return (status); -} - -#endif /* MBEDTLS_PSA_CRYPTO_C */ diff --git a/components/TARGET_PSA/services/inc/autogen_sid.h b/components/TARGET_PSA/services/inc/autogen_sid.h deleted file mode 100644 index d344068..0000000 --- a/components/TARGET_PSA/services/inc/autogen_sid.h +++ /dev/null @@ -1,111 +0,0 @@ -/* Copyright (c) 2019 ARM Limited - * - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/******************************************************************************* - * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - * THIS FILE IS AN AUTO-GENERATED FILE - DO NOT MODIFY IT. - * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - * Template Version 1.0 - * Generated by tools/psa/generate_partition_code.py Version 1.1 - ******************************************************************************/ - -/****************** Service Partitions ****************************************/ - -/* ----------------------------------------------------------------------------- - * ATTEST_SRV Service IDs - * -------------------------------------------------------------------------- */ - -#define PSA_ATTEST_GET_TOKEN_ID 0x00000F10 -#define PSA_ATTEST_GET_TOKEN_SIZE_ID 0x00000F11 -#define PSA_ATTEST_INJECT_KEY_ID 0x00000F12 - -/* ----------------------------------------------------------------------------- - * CRYPTO_SRV Service IDs - * -------------------------------------------------------------------------- */ - -#define PSA_CRYPTO_INIT_ID 0x00000F00 -#define PSA_MAC_ID 0x00000F01 -#define PSA_HASH_ID 0x00000F02 -#define PSA_ASYMMETRIC_ID 0x00000F03 -#define PSA_SYMMETRIC_ID 0x00000F04 -#define PSA_AEAD_ID 0x00000F05 -#define PSA_KEY_MNG_ID 0x00000F06 -#define PSA_RNG_ID 0x00000F07 -#define PSA_CRYPTO_FREE_ID 0x00000F08 -#define PSA_KEY_DERIVATION_ID 0x00000F09 -#define PSA_ENTROPY_ID 0x00000F0A - -/* ----------------------------------------------------------------------------- - * PLATFORM Service IDs - * -------------------------------------------------------------------------- */ - -#define PSA_PLATFORM_LC_GET 0x00011000 -#define PSA_PLATFORM_LC_SET 0x00011001 -#define PSA_PLATFORM_SYSTEM_RESET 0x00011002 -#define PSA_PLATFORM_IOCTL 0x00011003 - -/* ----------------------------------------------------------------------------- - * ITS Service IDs - * -------------------------------------------------------------------------- */ - -#define PSA_ITS_GET 0x00011A00 -#define PSA_ITS_SET 0x00011A01 -#define PSA_ITS_INFO 0x00011A02 -#define PSA_ITS_REMOVE 0x00011A03 -#define PSA_ITS_RESET 0x00011A04 - -/****************** Test Partitions *******************************************/ - -/* ----------------------------------------------------------------------------- - * CRYPTO_ACL_TEST Service IDs - * -------------------------------------------------------------------------- */ - -#define CRYPTO_GENERATE_KEY 0x00000201 -#define CRYPTO_OPEN_KEY 0x00000202 -#define CRYPTO_CLOSE_KEY 0x00000203 -#define CRYPTO_DESTROY_KEY 0x00000205 -#define CRYPTO_GET_KEY_ATTRIBUTES 0x00000206 -#define CRYPTO_IMPORT_KEY 0x00000208 - -/* ----------------------------------------------------------------------------- - * CLIENT_TESTS_PART1 Service IDs - * -------------------------------------------------------------------------- */ - -#define CLIENT_TESTS_PART1_ROT_SRV1 0x00001A05 -#define CLIENT_TESTS_PART1_DROP_CONN 0x00001A06 -#define CLIENT_TESTS_PART1_SECURE_CLIENTS_ONLY 0x00001A07 - -/* ----------------------------------------------------------------------------- - * SERVER_TESTS_PART1 Service IDs - * -------------------------------------------------------------------------- */ - -#define SERVER_TESTS_PART1_CONTROL 0x00001A01 -#define SERVER_TESTS_PART1_TEST 0x00001A02 - -/* ----------------------------------------------------------------------------- - * SERVER_TESTS_PART2 Service IDs - * -------------------------------------------------------------------------- */ - -#define SERVER_TESTS_PART2_ROT_SRV_REVERSE 0x00001A03 -#define SERVER_TESTS_PART2_ROT_SRV_DB_TST 0x00001A04 - -/* ----------------------------------------------------------------------------- - * SMOKE_TESTS_PART1 Service IDs - * -------------------------------------------------------------------------- */ - -#define SMOKE_TESTS_PART1_ROT_SRV1 0x00001A00 - diff --git a/components/TARGET_PSA/services/inc/mbed_spm_partitions.h b/components/TARGET_PSA/services/inc/mbed_spm_partitions.h deleted file mode 100644 index acf4122..0000000 --- a/components/TARGET_PSA/services/inc/mbed_spm_partitions.h +++ /dev/null @@ -1,310 +0,0 @@ -/* Copyright (c) 2017-2019 ARM Limited - * - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/******************************************************************************* - * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - * THIS FILE IS AN AUTO-GENERATED FILE - DO NOT MODIFY IT. - * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - * Template Version 1.0 - * Generated by tools/psa/generate_partition_code.py Version 1.1 - ******************************************************************************/ - -#ifndef __MBED_SPM_PARTITIONS_H___ -#define __MBED_SPM_PARTITIONS_H___ - - -/****************** Common definitions ****************************************/ - -/* PSA reserved event flags */ -#define PSA_RESERVED1_POS (1UL) -#define PSA_RESERVED1_MSK (1UL << PSA_RESERVED1_POS) - -#define PSA_RESERVED2_POS (2UL) -#define PSA_RESERVED2_MSK (1UL << PSA_RESERVED2_POS) - -/****************** Service Partitions ****************************************/ - -/* ----------------------------------------------------------------------------- - * ATTEST_SRV defines - * -------------------------------------------------------------------------- */ -#define ATTEST_SRV_ID 37 - -#define ATTEST_SRV_ROT_SRV_COUNT (3UL) -#define ATTEST_SRV_EXT_ROT_SRV_COUNT (7UL) - - -#define ATTEST_SRV_WAIT_ANY_IRQ_MSK (0) - -#define PSA_ATTEST_GET_TOKEN_POS (4UL) -#define PSA_ATTEST_GET_TOKEN (1UL << PSA_ATTEST_GET_TOKEN_POS) -#define PSA_ATTEST_GET_TOKEN_SIZE_POS (5UL) -#define PSA_ATTEST_GET_TOKEN_SIZE (1UL << PSA_ATTEST_GET_TOKEN_SIZE_POS) -#define PSA_ATTEST_INJECT_KEY_POS (6UL) -#define PSA_ATTEST_INJECT_KEY (1UL << PSA_ATTEST_INJECT_KEY_POS) - -#define ATTEST_SRV_WAIT_ANY_SID_MSK (\ - PSA_ATTEST_GET_TOKEN | \ - PSA_ATTEST_GET_TOKEN_SIZE | \ - PSA_ATTEST_INJECT_KEY) - - -/* ----------------------------------------------------------------------------- - * CRYPTO_SRV defines - * -------------------------------------------------------------------------- */ -#define CRYPTO_SRV_ID 35 - -#define CRYPTO_SRV_ROT_SRV_COUNT (11UL) -#define CRYPTO_SRV_EXT_ROT_SRV_COUNT (4UL) - - -#define CRYPTO_SRV_WAIT_ANY_IRQ_MSK (0) - -#define PSA_CRYPTO_INIT_POS (4UL) -#define PSA_CRYPTO_INIT (1UL << PSA_CRYPTO_INIT_POS) -#define PSA_MAC_POS (5UL) -#define PSA_MAC (1UL << PSA_MAC_POS) -#define PSA_HASH_POS (6UL) -#define PSA_HASH (1UL << PSA_HASH_POS) -#define PSA_ASYMMETRIC_POS (7UL) -#define PSA_ASYMMETRIC (1UL << PSA_ASYMMETRIC_POS) -#define PSA_SYMMETRIC_POS (8UL) -#define PSA_SYMMETRIC (1UL << PSA_SYMMETRIC_POS) -#define PSA_AEAD_POS (9UL) -#define PSA_AEAD (1UL << PSA_AEAD_POS) -#define PSA_KEY_MNG_POS (10UL) -#define PSA_KEY_MNG (1UL << PSA_KEY_MNG_POS) -#define PSA_RNG_POS (11UL) -#define PSA_RNG (1UL << PSA_RNG_POS) -#define PSA_CRYPTO_FREE_POS (12UL) -#define PSA_CRYPTO_FREE (1UL << PSA_CRYPTO_FREE_POS) -#define PSA_KEY_DERIVATION_POS (13UL) -#define PSA_KEY_DERIVATION (1UL << PSA_KEY_DERIVATION_POS) -#define PSA_ENTROPY_INJECT_POS (14UL) -#define PSA_ENTROPY_INJECT (1UL << PSA_ENTROPY_INJECT_POS) - -#define CRYPTO_SRV_WAIT_ANY_SID_MSK (\ - PSA_CRYPTO_INIT | \ - PSA_MAC | \ - PSA_HASH | \ - PSA_ASYMMETRIC | \ - PSA_SYMMETRIC | \ - PSA_AEAD | \ - PSA_KEY_MNG | \ - PSA_RNG | \ - PSA_CRYPTO_FREE | \ - PSA_KEY_DERIVATION | \ - PSA_ENTROPY_INJECT) - - -/* ----------------------------------------------------------------------------- - * PLATFORM defines - * -------------------------------------------------------------------------- */ -#define PLATFORM_ID 8 - -#define PLATFORM_ROT_SRV_COUNT (4UL) -#define PLATFORM_EXT_ROT_SRV_COUNT (1UL) - - -#define PLATFORM_WAIT_ANY_IRQ_MSK (0) - -#define PSA_PLATFORM_LC_GET_MSK_POS (4UL) -#define PSA_PLATFORM_LC_GET_MSK (1UL << PSA_PLATFORM_LC_GET_MSK_POS) -#define PSA_PLATFORM_LC_SET_MSK_POS (5UL) -#define PSA_PLATFORM_LC_SET_MSK (1UL << PSA_PLATFORM_LC_SET_MSK_POS) -#define PSA_PLATFORM_SYSTEM_RESET_MSK_POS (6UL) -#define PSA_PLATFORM_SYSTEM_RESET_MSK (1UL << PSA_PLATFORM_SYSTEM_RESET_MSK_POS) -#define PSA_PLATFORM_IOCTL_MSK_POS (7UL) -#define PSA_PLATFORM_IOCTL_MSK (1UL << PSA_PLATFORM_IOCTL_MSK_POS) - -#define PLATFORM_WAIT_ANY_SID_MSK (\ - PSA_PLATFORM_LC_GET_MSK | \ - PSA_PLATFORM_LC_SET_MSK | \ - PSA_PLATFORM_SYSTEM_RESET_MSK | \ - PSA_PLATFORM_IOCTL_MSK) - - -/* ----------------------------------------------------------------------------- - * ITS defines - * -------------------------------------------------------------------------- */ -#define ITS_ID 10 - -#define ITS_ROT_SRV_COUNT (5UL) -#define ITS_EXT_ROT_SRV_COUNT (0UL) - - -#define ITS_WAIT_ANY_IRQ_MSK (0) - -#define PSA_ITS_GET_MSK_POS (4UL) -#define PSA_ITS_GET_MSK (1UL << PSA_ITS_GET_MSK_POS) -#define PSA_ITS_SET_MSK_POS (5UL) -#define PSA_ITS_SET_MSK (1UL << PSA_ITS_SET_MSK_POS) -#define PSA_ITS_INFO_MSK_POS (6UL) -#define PSA_ITS_INFO_MSK (1UL << PSA_ITS_INFO_MSK_POS) -#define PSA_ITS_REMOVE_MSK_POS (7UL) -#define PSA_ITS_REMOVE_MSK (1UL << PSA_ITS_REMOVE_MSK_POS) -#define PSA_ITS_RESET_MSK_POS (8UL) -#define PSA_ITS_RESET_MSK (1UL << PSA_ITS_RESET_MSK_POS) - -#define ITS_WAIT_ANY_SID_MSK (\ - PSA_ITS_GET_MSK | \ - PSA_ITS_SET_MSK | \ - PSA_ITS_INFO_MSK | \ - PSA_ITS_REMOVE_MSK | \ - PSA_ITS_RESET_MSK) - - - -/****************** Test Partitions *******************************************/ - -#ifdef USE_PSA_TEST_PARTITIONS - -#ifdef USE_CRYPTO_ACL_TEST -/* ----------------------------------------------------------------------------- - * CRYPTO_ACL_TEST defines - * -------------------------------------------------------------------------- */ -#define CRYPTO_ACL_TEST_ID 128 - -#define CRYPTO_ACL_TEST_ROT_SRV_COUNT (6UL) -#define CRYPTO_ACL_TEST_EXT_ROT_SRV_COUNT (1UL) - - -#define CRYPTO_ACL_TEST_WAIT_ANY_IRQ_MSK (0) - -#define CRYPTO_GENERATE_KEY_MSK_POS (4UL) -#define CRYPTO_GENERATE_KEY_MSK (1UL << CRYPTO_GENERATE_KEY_MSK_POS) -#define CRYPTO_OPEN_KEY_MSK_POS (5UL) -#define CRYPTO_OPEN_KEY_MSK (1UL << CRYPTO_OPEN_KEY_MSK_POS) -#define CRYPTO_CLOSE_KEY_MSK_POS (6UL) -#define CRYPTO_CLOSE_KEY_MSK (1UL << CRYPTO_CLOSE_KEY_MSK_POS) -#define CRYPTO_DESTROY_KEY_MSK_POS (7UL) -#define CRYPTO_DESTROY_KEY_MSK (1UL << CRYPTO_DESTROY_KEY_MSK_POS) -#define CRYPTO_GET_KEY_ATTRIBUTES_MSK_POS (8UL) -#define CRYPTO_GET_KEY_ATTRIBUTES_MSK (1UL << CRYPTO_GET_KEY_ATTRIBUTES_MSK_POS) -#define CRYPTO_IMPORT_KEY_MSK_POS (9UL) -#define CRYPTO_IMPORT_KEY_MSK (1UL << CRYPTO_IMPORT_KEY_MSK_POS) - -#define CRYPTO_ACL_TEST_WAIT_ANY_SID_MSK (\ - CRYPTO_GENERATE_KEY_MSK | \ - CRYPTO_OPEN_KEY_MSK | \ - CRYPTO_CLOSE_KEY_MSK | \ - CRYPTO_DESTROY_KEY_MSK | \ - CRYPTO_GET_KEY_ATTRIBUTES_MSK | \ - CRYPTO_IMPORT_KEY_MSK) - - -#endif // USE_CRYPTO_ACL_TEST - -#ifdef USE_CLIENT_TESTS_PART1 -/* ----------------------------------------------------------------------------- - * CLIENT_TESTS_PART1 defines - * -------------------------------------------------------------------------- */ -#define CLIENT_TESTS_PART1_ID 1 - -#define CLIENT_TESTS_PART1_ROT_SRV_COUNT (3UL) -#define CLIENT_TESTS_PART1_EXT_ROT_SRV_COUNT (0UL) - - -#define CLIENT_TESTS_PART1_WAIT_ANY_IRQ_MSK (0) - -#define PART1_ROT_SRV1_MSK_POS (4UL) -#define PART1_ROT_SRV1_MSK (1UL << PART1_ROT_SRV1_MSK_POS) -#define DROP_CONN_MSK_POS (5UL) -#define DROP_CONN_MSK (1UL << DROP_CONN_MSK_POS) -#define SECURE_CLIENTS_ONLY_MSK_POS (6UL) -#define SECURE_CLIENTS_ONLY_MSK (1UL << SECURE_CLIENTS_ONLY_MSK_POS) - -#define CLIENT_TESTS_PART1_WAIT_ANY_SID_MSK (\ - PART1_ROT_SRV1_MSK | \ - DROP_CONN_MSK | \ - SECURE_CLIENTS_ONLY_MSK) - - -#endif // USE_CLIENT_TESTS_PART1 - -#ifdef USE_SERVER_TESTS_PART1 -/* ----------------------------------------------------------------------------- - * SERVER_TESTS_PART1 defines - * -------------------------------------------------------------------------- */ -#define SERVER_TESTS_PART1_ID 2 - -#define SERVER_TESTS_PART1_ROT_SRV_COUNT (2UL) -#define SERVER_TESTS_PART1_EXT_ROT_SRV_COUNT (2UL) - - -#define SERVER_TESTS_PART1_WAIT_ANY_IRQ_MSK (0) - -#define CONTROL_MSK_POS (4UL) -#define CONTROL_MSK (1UL << CONTROL_MSK_POS) -#define TEST_MSK_POS (5UL) -#define TEST_MSK (1UL << TEST_MSK_POS) - -#define SERVER_TESTS_PART1_WAIT_ANY_SID_MSK (\ - CONTROL_MSK | \ - TEST_MSK) - - -#endif // USE_SERVER_TESTS_PART1 - -#ifdef USE_SERVER_TESTS_PART2 -/* ----------------------------------------------------------------------------- - * SERVER_TESTS_PART2 defines - * -------------------------------------------------------------------------- */ -#define SERVER_TESTS_PART2_ID 3 - -#define SERVER_TESTS_PART2_ROT_SRV_COUNT (2UL) -#define SERVER_TESTS_PART2_EXT_ROT_SRV_COUNT (0UL) - - -#define SERVER_TESTS_PART2_WAIT_ANY_IRQ_MSK (0) - -#define ROT_SRV_REVERSE_MSK_POS (4UL) -#define ROT_SRV_REVERSE_MSK (1UL << ROT_SRV_REVERSE_MSK_POS) -#define ROT_SRV_DB_TST_MSK_POS (5UL) -#define ROT_SRV_DB_TST_MSK (1UL << ROT_SRV_DB_TST_MSK_POS) - -#define SERVER_TESTS_PART2_WAIT_ANY_SID_MSK (\ - ROT_SRV_REVERSE_MSK | \ - ROT_SRV_DB_TST_MSK) - - -#endif // USE_SERVER_TESTS_PART2 - -#ifdef USE_SMOKE_TESTS_PART1 -/* ----------------------------------------------------------------------------- - * SMOKE_TESTS_PART1 defines - * -------------------------------------------------------------------------- */ -#define SMOKE_TESTS_PART1_ID 4 - -#define SMOKE_TESTS_PART1_ROT_SRV_COUNT (1UL) -#define SMOKE_TESTS_PART1_EXT_ROT_SRV_COUNT (0UL) - - -#define SMOKE_TESTS_PART1_WAIT_ANY_IRQ_MSK (0) - -#define ROT_SRV1_MSK_POS (4UL) -#define ROT_SRV1_MSK (1UL << ROT_SRV1_MSK_POS) - -#define SMOKE_TESTS_PART1_WAIT_ANY_SID_MSK (\ - ROT_SRV1_MSK) - - -#endif // USE_SMOKE_TESTS_PART1 - - -#endif // USE_PSA_TEST_PARTITIONS - -#endif // __MBED_SPM_PARTITIONS_H___ diff --git a/components/TARGET_PSA/services/platform/COMPONENT_PSA_SRV_EMUL/platform_emul.c b/components/TARGET_PSA/services/platform/COMPONENT_PSA_SRV_EMUL/platform_emul.c deleted file mode 100644 index 8523413..0000000 --- a/components/TARGET_PSA/services/platform/COMPONENT_PSA_SRV_EMUL/platform_emul.c +++ /dev/null @@ -1,40 +0,0 @@ -/* Copyright (c) 2019 ARM Limited - * - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "psa/lifecycle.h" -#include "platform_srv_impl.h" - -uint32_t psa_security_lifecycle_state(void) -{ - uint32_t lc_state = 0; - psa_status_t status = PSA_SUCCESS; - status = psa_platfrom_lifecycle_get_impl(&lc_state); - if (status != PSA_SUCCESS) { - lc_state = PSA_LIFECYCLE_UNKNOWN; - } - return lc_state; -} - -psa_status_t mbed_psa_reboot_and_request_new_security_state(uint32_t new_state) -{ - return psa_platfrom_lifecycle_change_request_impl(new_state); -} - -void mbed_psa_system_reset(void) -{ - mbed_psa_system_reset_impl(); -} diff --git a/components/TARGET_PSA/services/platform/COMPONENT_PSA_SRV_IMPL/platform_srv_impl.c b/components/TARGET_PSA/services/platform/COMPONENT_PSA_SRV_IMPL/platform_srv_impl.c deleted file mode 100644 index 9854633..0000000 --- a/components/TARGET_PSA/services/platform/COMPONENT_PSA_SRV_IMPL/platform_srv_impl.c +++ /dev/null @@ -1,56 +0,0 @@ -/* Copyright (c) 2019-2020 Arm Limited - * - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "psa/lifecycle.h" -#include "psa/internal_trusted_storage.h" -#include "platform_srv_impl.h" -#include "cmsis.h" - -#ifndef MBED_CONF_LIFECYCLE_STATE -#define MBED_CONF_LIFECYCLE_STATE PSA_LIFECYCLE_ASSEMBLY_AND_TEST -#endif - -psa_status_t psa_platfrom_lifecycle_get_impl(uint32_t *lc_state) -{ - *lc_state = MBED_CONF_LIFECYCLE_STATE; - return PSA_SUCCESS; -} - -psa_status_t psa_its_reset(); - -psa_status_t psa_platfrom_lifecycle_change_request_impl(uint32_t state) -{ - if (PSA_LIFECYCLE_ASSEMBLY_AND_TEST == state) { - return psa_its_reset(); - } - return PSA_ERROR_NOT_SUPPORTED; -} - -MBED_WEAK void mbed_psa_system_reset_impl(void) -{ - /* Reset the system */ - NVIC_SystemReset(); -} - -MBED_WEAK enum tfm_platform_err_t tfm_platform_hal_ioctl(tfm_platform_ioctl_req_t request, - psa_invec *in_vec, - psa_outvec *out_vec) -{ - (void)in_vec; - (void)out_vec; - return TFM_PLATFORM_ERR_NOT_SUPPORTED; -} diff --git a/components/TARGET_PSA/services/platform/COMPONENT_PSA_SRV_IMPL/platform_srv_impl.h b/components/TARGET_PSA/services/platform/COMPONENT_PSA_SRV_IMPL/platform_srv_impl.h deleted file mode 100644 index 29e704f..0000000 --- a/components/TARGET_PSA/services/platform/COMPONENT_PSA_SRV_IMPL/platform_srv_impl.h +++ /dev/null @@ -1,43 +0,0 @@ -/* Copyright (c) 2019-2020 Arm Limited - * - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef __PLATFROM_SRV_IMPL_H__ -#define __PLATFROM_SRV_IMPL_H__ - -#include "psa/client.h" -#include "psa/lifecycle.h" -#include "mbed_toolchain.h" -#include "tfm_platform_api.h" - -psa_status_t psa_platfrom_lifecycle_get_impl(uint32_t *lc_state); -psa_status_t psa_platfrom_lifecycle_change_request_impl(uint32_t lc_state); -MBED_NORETURN void mbed_psa_system_reset_impl(void); - -/*! - * \brief Performs a platform-specific service - * - * \param[in] request Request identifier (valid values vary - * based on the platform) - * \param[in] in_vec Input buffer to the requested service (or NULL) - * \param[out] out_vec Output buffer to the requested service (or NULL) - * - * \return Returns values as specified by the \ref tfm_platform_err_t - */ -enum tfm_platform_err_t tfm_platform_hal_ioctl(tfm_platform_ioctl_req_t request, - psa_invec *in_vec, - psa_outvec *out_vec); -#endif // __PLATFROM_SRV_IMPL_H__ diff --git a/components/TARGET_PSA/services/platform/COMPONENT_PSA_SRV_IPC/platform_ipc.c b/components/TARGET_PSA/services/platform/COMPONENT_PSA_SRV_IPC/platform_ipc.c deleted file mode 100644 index 92cf1cd..0000000 --- a/components/TARGET_PSA/services/platform/COMPONENT_PSA_SRV_IPC/platform_ipc.c +++ /dev/null @@ -1,118 +0,0 @@ -/* Copyright (c) 2019-2020 Arm Limited - * - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "psa_manifest/sid.h" -#include "psa/lifecycle.h" -#include "psa/client.h" -#include "mbed_toolchain.h" -#include "mbed_error.h" -#include "tfm_platform_api.h" - -uint32_t psa_security_lifecycle_state(void) -{ - psa_handle_t conn = psa_connect(PSA_PLATFORM_LC_GET, 1); - if (conn <= PSA_NULL_HANDLE) { - return PSA_LIFECYCLE_UNKNOWN; - } - - uint32_t lc_state = 0; - psa_outvec resp[1] = { {&lc_state, sizeof(lc_state)} }; - - psa_status_t status = psa_call(conn, NULL, 0, resp, 1); - if (status == PSA_DROP_CONNECTION) { - lc_state = PSA_LIFECYCLE_UNKNOWN; - } - - psa_close(conn); - - return lc_state; -} - -psa_status_t mbed_psa_reboot_and_request_new_security_state(uint32_t new_state) -{ - psa_handle_t conn = psa_connect(PSA_PLATFORM_LC_SET, 1); - if (conn <= PSA_NULL_HANDLE) { - return (psa_status_t) conn; - } - - psa_invec msg[1] = { - { &new_state, sizeof(new_state) } - }; - - psa_status_t status = psa_call(conn, msg, 1, NULL, 0); - - psa_close(conn); - return status; -} - -void mbed_psa_system_reset(void) -{ - psa_handle_t conn = psa_connect(PSA_PLATFORM_SYSTEM_RESET, 1); - if (conn > PSA_NULL_HANDLE) { - psa_call(conn, NULL, 0, NULL, 0); - } - error("reset failed - cannot connect to service handle=%ld", conn); -} - -enum tfm_platform_err_t -tfm_platform_ioctl(tfm_platform_ioctl_req_t request, - psa_invec *input, psa_outvec *output) { - tfm_platform_ioctl_req_t req = request; - struct psa_invec in_vec[2] = { {0} }; - size_t inlen, outlen; - psa_status_t status = PSA_ERROR_CONNECTION_REFUSED; - psa_handle_t handle = PSA_NULL_HANDLE; - - in_vec[0].base = &req; - in_vec[0].len = sizeof(req); - if (input != NULL) - { - in_vec[1].base = input->base; - in_vec[1].len = input->len; - inlen = 2; - } else - { - inlen = 1; - } - - if (output != NULL) - { - outlen = 1; - } else - { - outlen = 0; - } - - handle = psa_connect(PSA_PLATFORM_IOCTL, 1); - if (handle <= 0) - { - return TFM_PLATFORM_ERR_SYSTEM_ERROR; - } - - status = psa_call(handle, - in_vec, inlen, - output, outlen); - psa_close(handle); - - if (status < PSA_SUCCESS) - { - return TFM_PLATFORM_ERR_SYSTEM_ERROR; - } else - { - return (enum tfm_platform_err_t) status; - } -} diff --git a/components/TARGET_PSA/services/storage/common/psa_storage_common_impl.cpp b/components/TARGET_PSA/services/storage/common/psa_storage_common_impl.cpp deleted file mode 100644 index 1f68596..0000000 --- a/components/TARGET_PSA/services/storage/common/psa_storage_common_impl.cpp +++ /dev/null @@ -1,287 +0,0 @@ -/* Copyright (c) 2018 ARM Limited - * - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include "TDBStore.h" -#include "psa_storage_common_impl.h" -#include "mbed_error.h" -#include "mbed_assert.h" -#include "mbed_toolchain.h" - -using namespace mbed; - -#ifdef __cplusplus -extern "C" -{ -#endif - -// Maximum length of filename we use for kvstore API. -// pid: 6; delimiter: 1; uid: 11; str terminator: 1 -#define PSA_STORAGE_FILE_NAME_MAX 19 - -#define FLAGS_MSK PSA_STORAGE_FLAG_WRITE_ONCE - -#define STR_EXPAND(tok) #tok - -const uint8_t base64_coding_table[] = { - 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', - 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', - 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', - 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', - 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', - 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', - 'w', 'x', 'y', 'z', '0', '1', '2', '3', - '4', '5', '6', '7', '8', '9', '+', '-' -}; - -void psa_storage_handle_version(KVStore *kvstore, const char *version_key, const psa_storage_version_t *curr_version, - migrate_func_t migrate_func) -{ - psa_storage_version_t read_version = {0, 0}; - size_t actual_size = 0; - bool write_version = false; - int status = kvstore->get(version_key, &read_version, sizeof(read_version), &actual_size, 0); - if (status == MBED_SUCCESS) { - if (actual_size != sizeof(read_version)) { - error("PSA storage version data is corrupt"); - } - } else if (status == MBED_ERROR_ITEM_NOT_FOUND) { - write_version = true; - } else { - error("Could not read PSA storage version data"); - } - - if ((read_version.major > curr_version->major) || - ((read_version.major == curr_version->major) && (read_version.minor > curr_version->minor))) { - error("Downgrading PSA storage version is not allowed"); - } - - if ((read_version.major < curr_version->major) || - ((read_version.major == curr_version->major) && (read_version.minor < curr_version->minor))) { - psa_status_t migration_status = migrate_func(kvstore, &read_version, curr_version); - if (migration_status != PSA_SUCCESS) { - error("PSA storage migration failed"); - } - - write_version = true; - } - - if (write_version) { - if (kvstore->set(version_key, curr_version, sizeof(psa_storage_version_t), 0) != MBED_SUCCESS) { - error("Could not write PSA storage version"); - } - } -} - -/* - * \brief Convert KVStore stauts codes to PSA internal storage status codes - * - * \param[in] status - KVStore status code - * \return PSA internal storage status code - */ -static psa_status_t convert_status(int status) -{ - switch (status) { - case MBED_SUCCESS: - return PSA_SUCCESS; - case MBED_ERROR_WRITE_PROTECTED: - return PSA_ERROR_NOT_PERMITTED; - case MBED_ERROR_MEDIA_FULL: - return PSA_ERROR_INSUFFICIENT_STORAGE; - case MBED_ERROR_ITEM_NOT_FOUND: - return PSA_ERROR_DOES_NOT_EXIST; - case MBED_ERROR_INVALID_DATA_DETECTED: - return PSA_ERROR_DATA_CORRUPT; - case MBED_ERROR_INVALID_ARGUMENT: - return PSA_ERROR_INVALID_ARGUMENT; - case MBED_ERROR_READ_FAILED: // fallthrough - case MBED_ERROR_WRITE_FAILED: - return PSA_ERROR_STORAGE_FAILURE; - case MBED_ERROR_AUTHENTICATION_FAILED: // fallthrough - case MBED_ERROR_RBP_AUTHENTICATION_FAILED: - return PSA_ERROR_INVALID_SIGNATURE; - default: - return PSA_ERROR_GENERIC_ERROR; - } -} - -/* - * \brief Logic shift right - * - * \note must operate on unsinged integers to prevent negative carry - * \param x[in] input number for shifting - * \param n[in] number of bits to shift right - * \return the result - */ -static MBED_FORCEINLINE uint32_t lsr32(uint32_t x, uint32_t n) -{ - return x >> n; -} - -/* - * \brief Logic shift right - * - * \note must operate on unsinged integers to prevent negative carry - * \param x[in] input number for shifting - * \param n[in] number of bits to shift right - * \return the result - */ -static MBED_FORCEINLINE uint64_t lsr64(uint64_t x, uint32_t n) -{ - return x >> n; -} - -/* - * \breif Generate KVStore file name - * - * Generate KVStore file name by Base64 encoding PID and UID with a delimiter. - * Delimiter is required for determining between PID and UID. - * - * \param[out] tdb_filename - pointer to a buffer for the file name - * \param[in] tdb_filename_size - output buffer size - * \param[in] uid - PSA internal storage unique ID - * \param[in] pid - owner PSA partition ID - */ -static void generate_fn(char *tdb_filename, uint32_t tdb_filename_size, psa_storage_uid_t uid, int32_t pid) -{ - MBED_ASSERT(tdb_filename != NULL); - MBED_ASSERT(tdb_filename_size == PSA_STORAGE_FILE_NAME_MAX); - - uint8_t filename_idx = 0; - uint32_t unsigned_pid = (uint32_t)pid; // binary only representation for bitwise operations - - // Iterate on PID; each time convert 6 bits of PID into a character; first iteration must be done - do { - tdb_filename[filename_idx++] = base64_coding_table[unsigned_pid & 0x3F]; - unsigned_pid = lsr32(unsigned_pid, 6); - } while (unsigned_pid != 0); - - // Write delimiter - tdb_filename[filename_idx++] = '#'; - - // Iterate on UID; each time convert 6 bits of UID into a character; first iteration must be done - do { - tdb_filename[filename_idx++] = base64_coding_table[uid & 0x3F]; - uid = lsr64(uid, 6); - } while (uid != 0); - - tdb_filename[filename_idx++] = '\0'; - MBED_ASSERT(filename_idx <= PSA_STORAGE_FILE_NAME_MAX); -} - -psa_status_t psa_storage_set_impl(KVStore *kvstore, int32_t pid, psa_storage_uid_t uid, - size_t data_length, const void *p_data, - uint32_t kv_create_flags) -{ - if (uid == 0) { - return PSA_ERROR_INVALID_ARGUMENT; - } - // Generate KVStore key - char kv_key[PSA_STORAGE_FILE_NAME_MAX] = {'\0'}; - generate_fn(kv_key, PSA_STORAGE_FILE_NAME_MAX, uid, pid); - - int status = kvstore->set(kv_key, p_data, data_length, kv_create_flags); - - return convert_status(status); -} - -psa_status_t psa_storage_get_impl(KVStore *kvstore, int32_t pid, psa_storage_uid_t uid, - size_t data_offset, size_t data_length, void *p_data, size_t *p_data_length) -{ - if (uid == 0) { - return PSA_ERROR_INVALID_ARGUMENT; - } - - // Generate KVStore key - char kv_key[PSA_STORAGE_FILE_NAME_MAX] = {'\0'}; - generate_fn(kv_key, PSA_STORAGE_FILE_NAME_MAX, uid, pid); - - KVStore::info_t kv_info; - int status = kvstore->get_info(kv_key, &kv_info); - - if (status == MBED_SUCCESS) { - if (data_offset > kv_info.size) { - return PSA_ERROR_INVALID_ARGUMENT; - } - - // Verify (size + offset) does not wrap around - if (data_length + data_offset < data_length) { - return PSA_ERROR_INVALID_ARGUMENT; - } - - if (data_offset + data_length > kv_info.size) { - return PSA_ERROR_BUFFER_TOO_SMALL; - } - - status = kvstore->get(kv_key, p_data, data_length, p_data_length, data_offset); - } - - return convert_status(status); -} - -psa_status_t psa_storage_get_info_impl(KVStore *kvstore, int32_t pid, psa_storage_uid_t uid, - struct psa_storage_info_t *p_info, uint32_t *kv_get_flags) -{ - - if (uid == 0) { - return PSA_ERROR_INVALID_ARGUMENT; - } - - // Generate KVStore key - char kv_key[PSA_STORAGE_FILE_NAME_MAX] = {'\0'}; - generate_fn(kv_key, PSA_STORAGE_FILE_NAME_MAX, uid, pid); - - KVStore::info_t kv_info; - int status = kvstore->get_info(kv_key, &kv_info); - - if (status == MBED_SUCCESS) { - p_info->flags = 0; - if (kv_info.flags & KVStore::WRITE_ONCE_FLAG) { - p_info->flags |= PSA_STORAGE_FLAG_WRITE_ONCE; - } - *kv_get_flags = kv_info.flags; - p_info->size = kv_info.size; - p_info->capacity = kv_info.size; - } - - return convert_status(status); -} - -psa_status_t psa_storage_remove_impl(KVStore *kvstore, int32_t pid, psa_storage_uid_t uid) -{ - if (uid == 0) { - return PSA_ERROR_INVALID_ARGUMENT; - } - - // Generate KVStore key - char kv_key[PSA_STORAGE_FILE_NAME_MAX] = {'\0'}; - generate_fn(kv_key, PSA_STORAGE_FILE_NAME_MAX, uid, pid); - - int status = kvstore->remove(kv_key); - - return convert_status(status); -} - -psa_status_t psa_storage_reset_impl(KVStore *kvstore) -{ - int status = kvstore->reset(); - return convert_status(status); -} - -#ifdef __cplusplus -} -#endif diff --git a/components/TARGET_PSA/services/storage/common/psa_storage_common_impl.h b/components/TARGET_PSA/services/storage/common/psa_storage_common_impl.h deleted file mode 100644 index 86f3617..0000000 --- a/components/TARGET_PSA/services/storage/common/psa_storage_common_impl.h +++ /dev/null @@ -1,50 +0,0 @@ -/* Copyright (c) 2019 ARM Limited - * - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef __PSA_STORAGE_COMMON_IMPL_H__ -#define __PSA_STORAGE_COMMON_IMPL_H__ - -#include "psa/error.h" -#include "psa/storage_common.h" -#include "KVStore.h" - -#ifdef __cplusplus -extern "C" -{ -#endif - -typedef struct { - uint32_t major; - uint32_t minor; -} psa_storage_version_t; - -typedef psa_status_t (*migrate_func_t)(mbed::KVStore *kvstore, const psa_storage_version_t *old_version, const psa_storage_version_t *new_version); - -void psa_storage_handle_version(mbed::KVStore *kvstore, const char *version_key, const psa_storage_version_t *version, - migrate_func_t migrate_func); -psa_status_t psa_storage_set_impl(mbed::KVStore *kvstore, int32_t pid, psa_storage_uid_t uid, size_t data_length, const void *p_data, uint32_t kv_create_flags); -psa_status_t psa_storage_get_impl(mbed::KVStore *kvstore, int32_t pid, psa_storage_uid_t uid, size_t data_offset, size_t data_length, void *p_data, size_t *p_data_length); -psa_status_t psa_storage_get_info_impl(mbed::KVStore *kvstore, int32_t pid, psa_storage_uid_t uid, struct psa_storage_info_t *p_info, uint32_t *kv_get_flags); -psa_status_t psa_storage_remove_impl(mbed::KVStore *kvstore, int32_t pid, psa_storage_uid_t uid); -psa_status_t psa_storage_reset_impl(mbed::KVStore *kvstore); - -#ifdef __cplusplus -} -#endif - - -#endif // __PSA_STORAGE_COMMON_IMPL_H__ diff --git a/components/TARGET_PSA/services/storage/its/COMPONENT_PSA_SRV_EMUL/psa_prot_internal_storage.cpp b/components/TARGET_PSA/services/storage/its/COMPONENT_PSA_SRV_EMUL/psa_prot_internal_storage.cpp deleted file mode 100644 index bce3709..0000000 --- a/components/TARGET_PSA/services/storage/its/COMPONENT_PSA_SRV_EMUL/psa_prot_internal_storage.cpp +++ /dev/null @@ -1,108 +0,0 @@ -/* Copyright (c) 2018 ARM Limited - * - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include - -#include "psa/internal_trusted_storage.h" -#include "psa/storage_common.h" -#include "pits_impl.h" -#include "kv_config.h" -#include "mbed_error.h" - -// In EMUL world, there is no real partitioning, which makes the source partition irrelevant. -// So here we set a global pid value to be used for when calling IMPL functions -#define PSA_ITS_EMUL_PID 1 - -psa_status_t psa_its_set(psa_storage_uid_t uid, size_t data_length, const void *p_data, psa_storage_create_flags_t create_flags) -{ - if (!p_data && data_length) { - return PSA_ERROR_INVALID_ARGUMENT; - } - - // KVStore initiation: - // - In EMUL (non-secure single core) we do it here since we don't have another context to do it inside. - // - Repeating calls has no effect - int kv_status = kv_init_storage_config(); - if (kv_status != MBED_SUCCESS) { - return PSA_ERROR_STORAGE_FAILURE; - } - - psa_status_t res = psa_its_set_impl(PSA_ITS_EMUL_PID, uid, data_length, p_data, create_flags); - - return res; -} - -psa_status_t psa_its_get(psa_storage_uid_t uid, size_t data_offset, size_t data_length, void *p_data, size_t *p_data_length) -{ - if ((!p_data && data_length) || !p_data_length) { - return PSA_ERROR_INVALID_ARGUMENT; - } - - // KVStore initiation: - // - In EMUL (non-secure single core) we do it here since we don't have another context to do it inside. - // - Repeating calls has no effect - int kv_status = kv_init_storage_config(); - if (kv_status != MBED_SUCCESS) { - return PSA_ERROR_STORAGE_FAILURE; - } - - return psa_its_get_impl(PSA_ITS_EMUL_PID, uid, data_offset, data_length, p_data, p_data_length); -} - -psa_status_t psa_its_get_info(psa_storage_uid_t uid, struct psa_storage_info_t *p_info) -{ - if (!p_info) { - return PSA_ERROR_INVALID_ARGUMENT; - } - - // KVStore initiation: - // - In EMUL (non-secure single core) we do it here since we don't have another context to do it inside. - // - Repeating calls has no effect - int kv_status = kv_init_storage_config(); - if (kv_status != MBED_SUCCESS) { - return PSA_ERROR_STORAGE_FAILURE; - } - - return psa_its_get_info_impl(PSA_ITS_EMUL_PID, uid, p_info); -} - -psa_status_t psa_its_remove(psa_storage_uid_t uid) -{ - // KVStore initiation: - // - In EMUL (non-secure single core) we do it here since we don't have another context to do it inside. - // - Repeating calls has no effect - int kv_status = kv_init_storage_config(); - if (kv_status != MBED_SUCCESS) { - return PSA_ERROR_STORAGE_FAILURE; - } - - return psa_its_remove_impl(PSA_ITS_EMUL_PID, uid); -} - -extern "C" psa_status_t psa_its_reset() -{ - // KVStore initiation: - // - In EMUL (non-secure single core) we do it here since we don't have another context to do it inside. - // - Repeating calls has no effect - int kv_status = kv_init_storage_config(); - if (kv_status != MBED_SUCCESS) { - return PSA_ERROR_STORAGE_FAILURE; - } - - return psa_its_reset_impl(); -} diff --git a/components/TARGET_PSA/services/storage/its/COMPONENT_PSA_SRV_IMPL/TARGET_TFM/its_tfm_impl.cpp b/components/TARGET_PSA/services/storage/its/COMPONENT_PSA_SRV_IMPL/TARGET_TFM/its_tfm_impl.cpp deleted file mode 100644 index 46cd1a7..0000000 --- a/components/TARGET_PSA/services/storage/its/COMPONENT_PSA_SRV_IMPL/TARGET_TFM/its_tfm_impl.cpp +++ /dev/null @@ -1,157 +0,0 @@ -/* Copyright (c) 2018 ARM Limited - * - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include "KVStore.h" -#include "TDBStore.h" -#include "psa/internal_trusted_storage.h" -#include "pits_impl.h" -#include "mbed_error.h" -#include "mbed_toolchain.h" -#include "FlashIAP.h" -#include "FlashIAPBlockDevice.h" - -using namespace mbed; - -static KVStore *internal_store = NULL; -static bool is_tfm_kv_initialized = false; - -static inline uint32_t align_up(uint64_t val, uint64_t size) -{ - return (((val - 1) / size) + 1) * size; -} - -static inline uint32_t align_down(uint64_t val, uint64_t size) -{ - return (((val) / size)) * size; -} - -static BlockDevice *_get_blockdevice(bd_addr_t start_address, bd_size_t size) -{ - int ret = MBED_SUCCESS; - bd_addr_t flash_end_address; - bd_addr_t flash_start_address; - bd_addr_t aligned_start_address; - bd_addr_t aligned_end_address; - bd_addr_t end_address; - FlashIAP flash; - - ret = flash.init(); - if (ret != 0) { - return NULL; - } - - //Get flash parameters before starting - flash_start_address = flash.get_flash_start(); - flash_end_address = flash_start_address + flash.get_flash_size();; - - aligned_start_address = align_down(start_address, flash.get_sector_size(start_address)); - if (start_address != aligned_start_address) { - flash.deinit(); - return NULL; - } - - end_address = start_address + size; - if (end_address > flash_end_address) { - flash.deinit(); - return NULL; - } - - aligned_end_address = align_up(end_address, flash.get_sector_size(end_address - 1)); - if (end_address != aligned_end_address) { - flash.deinit(); - return NULL; - } - - static FlashIAPBlockDevice bd(start_address, size); - flash.deinit(); - return &bd; -} - -static int _calculate_blocksize_match_tdbstore(BlockDevice *bd) -{ - bd_size_t size = bd->size(); - bd_size_t erase_size = bd->get_erase_size(); - bd_size_t number_of_sector = size / erase_size; - - if (number_of_sector < 2) { - return -1; - } - - return 0; -} - -static int tfm_kv_init(void) -{ - int ret = MBED_SUCCESS; - bd_size_t internal_size = MBED_CONF_STORAGE_TDB_INTERNAL_INTERNAL_SIZE; - bd_addr_t internal_start_address = MBED_CONF_STORAGE_TDB_INTERNAL_INTERNAL_BASE_ADDRESS; - - //Get internal memory FLASHIAP block device. - BlockDevice *internal_bd = _get_blockdevice(internal_start_address, internal_size); - if (internal_bd == NULL) { - return -1; // TODO: Error code - } - - ret = internal_bd->init(); - if (ret != 0) { - return ret; - } - - //Check that internal flash has 2 or more sectors - if (_calculate_blocksize_match_tdbstore(internal_bd) != 0) { - return -1; // TODO: Error code - } - - //Deinitialize internal block device and TDB will reinitialize and take control on it. - ret = internal_bd->deinit(); - if (ret != 0) { - return ret; - } - - //Create a TDBStore in the internal FLASHIAP block device. - static TDBStore tdb_internal(internal_bd); - internal_store = &tdb_internal; - - ret = internal_store->init(); - - return ret; -} - -/* - * \brief Get default KVStore instance for internal flesh storage - * - * \return valid pointer to KVStore - */ - -KVStore *get_its_kvstore_instance(void) -{ - return internal_store; -} -extern "C" int kv_init_storage_config() -{ - int ret = MBED_SUCCESS; - - if (!is_tfm_kv_initialized) { - ret = tfm_kv_init(); - } - - is_tfm_kv_initialized = (ret == MBED_SUCCESS) ? true : false; - return ret; -} - - diff --git a/components/TARGET_PSA/services/storage/its/COMPONENT_PSA_SRV_IMPL/pits_impl.cpp b/components/TARGET_PSA/services/storage/its/COMPONENT_PSA_SRV_IMPL/pits_impl.cpp deleted file mode 100644 index 6f0835d..0000000 --- a/components/TARGET_PSA/services/storage/its/COMPONENT_PSA_SRV_IMPL/pits_impl.cpp +++ /dev/null @@ -1,147 +0,0 @@ -/* Copyright (c) 2019 ARM Limited - * - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include "KVStore.h" -#include "TDBStore.h" -#include "psa/internal_trusted_storage.h" -#include "psa_storage_common_impl.h" -#include "pits_impl.h" -#include "mbed_error.h" -#include "mbed_toolchain.h" - -using namespace mbed; - -#if defined(TARGET_TFM) -KVStore *get_its_kvstore_instance(void); -#else -#include "KVMap.h" -#endif - - - -#ifdef __cplusplus -extern "C" -{ -#endif - -#define STR_EXPAND(tok) #tok -#define ITS_VERSION_KEY "PSA_ITS_VERSION" // ITS version entry identifier in TDBStore - -static KVStore *kvstore = NULL; -static bool initialized = false; - - -MBED_WEAK psa_status_t its_version_migrate(KVStore *kvstore, - const psa_storage_version_t *old_version, const psa_storage_version_t *new_version) -{ - (void)kvstore; - (void)old_version; - (void)new_version; - return PSA_SUCCESS; -} - - -static void its_init(void) -{ -#if defined(TARGET_TFM) - kvstore = get_its_kvstore_instance(); -#else - KVMap &kv_map = KVMap::get_instance(); - kvstore = kv_map.get_internal_kv_instance(STR_EXPAND(MBED_CONF_STORAGE_DEFAULT_KV)); -#endif - psa_storage_version_t version = {PSA_ITS_API_VERSION_MAJOR, PSA_ITS_API_VERSION_MINOR}; - if (!kvstore) { - // Can only happen due to system misconfiguration. - // Thus considered as unrecoverable error for runtime. - error("Failed getting kvstore instance\n"); - } - - psa_storage_handle_version(kvstore, ITS_VERSION_KEY, &version, its_version_migrate); - initialized = true; -} - -// used from test only -void its_deinit(void) -{ - kvstore = NULL; - initialized = false; -} - - -psa_status_t psa_its_set_impl(int32_t pid, psa_storage_uid_t uid, size_t data_length, const void *p_data, psa_storage_create_flags_t create_flags) -{ - if (!initialized) { - its_init(); - } - - if (create_flags & ~PSA_STORAGE_FLAG_WRITE_ONCE) { - return PSA_ERROR_NOT_SUPPORTED; - } - - return psa_storage_set_impl(kvstore, pid, uid, data_length, p_data, create_flags); -} - -psa_status_t psa_its_get_impl(int32_t pid, psa_storage_uid_t uid, size_t data_offset, size_t data_length, void *p_data, size_t *p_data_length) -{ - if (!initialized) { - its_init(); - } - - return psa_storage_get_impl(kvstore, pid, uid, data_offset, data_length, p_data, p_data_length); -} - -psa_status_t psa_its_get_info_impl(int32_t pid, psa_storage_uid_t uid, struct psa_storage_info_t *p_info) -{ - uint32_t kv_get_flags; - if (!initialized) { - its_init(); - } - - return psa_storage_get_info_impl(kvstore, pid, uid, p_info, &kv_get_flags); -} - -psa_status_t psa_its_remove_impl(int32_t pid, psa_storage_uid_t uid) -{ - if (!initialized) { - its_init(); - } - - return psa_storage_remove_impl(kvstore, pid, uid); -} - -psa_status_t psa_its_reset_impl() -{ - // Do not call its_init here to avoid version check before reset -#if defined(TARGET_TFM) - kvstore = get_its_kvstore_instance(); -#else - KVMap &kv_map = KVMap::get_instance(); - kvstore = kv_map.get_internal_kv_instance(STR_EXPAND(MBED_CONF_STORAGE_DEFAULT_KV)); -#endif - if (!kvstore) { - // Can only happen due to system misconfiguration. - // Thus considered as unrecoverable error for runtime. - error("Failed getting kvstore instance\n"); - } - - return psa_storage_reset_impl(kvstore); -} - -#ifdef __cplusplus -} -#endif diff --git a/components/TARGET_PSA/services/storage/its/COMPONENT_PSA_SRV_IMPL/pits_impl.h b/components/TARGET_PSA/services/storage/its/COMPONENT_PSA_SRV_IMPL/pits_impl.h deleted file mode 100644 index 43d076d..0000000 --- a/components/TARGET_PSA/services/storage/its/COMPONENT_PSA_SRV_IMPL/pits_impl.h +++ /dev/null @@ -1,39 +0,0 @@ -/* Copyright (c) 2018 ARM Limited - * - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef __PITS_IMPL_H__ -#define __PITS_IMPL_H__ - -#include "psa/error.h" -#include "psa/storage_common.h" - -#ifdef __cplusplus -extern "C" -{ -#endif - -psa_status_t psa_its_set_impl(int32_t pid, psa_storage_uid_t uid, size_t data_length, const void *p_data, psa_storage_create_flags_t create_flags); -psa_status_t psa_its_get_impl(int32_t pid, psa_storage_uid_t uid, size_t data_offset, size_t data_length, void *p_data, size_t *p_data_length); -psa_status_t psa_its_get_info_impl(int32_t pid, psa_storage_uid_t uid, struct psa_storage_info_t *p_info); -psa_status_t psa_its_remove_impl(int32_t pid, psa_storage_uid_t uid); -psa_status_t psa_its_reset_impl(); - -#ifdef __cplusplus -} -#endif - -#endif // __PITS_IMPL_H__ diff --git a/components/TARGET_PSA/services/storage/its/COMPONENT_PSA_SRV_IPC/psa_prot_internal_storage.c b/components/TARGET_PSA/services/storage/its/COMPONENT_PSA_SRV_IPC/psa_prot_internal_storage.c deleted file mode 100644 index fb999af..0000000 --- a/components/TARGET_PSA/services/storage/its/COMPONENT_PSA_SRV_IPC/psa_prot_internal_storage.c +++ /dev/null @@ -1,137 +0,0 @@ -/* Copyright (c) 2018 ARM Limited - * - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "psa/client.h" -#include "psa/storage_common.h" -#include "psa/internal_trusted_storage.h" -#include "psa_manifest/sid.h" - -psa_status_t psa_its_set(psa_storage_uid_t uid, size_t data_length, const void *p_data, psa_storage_create_flags_t create_flags) -{ - if (!p_data && data_length) { - return PSA_ERROR_INVALID_ARGUMENT; - } - - psa_invec msg[3] = { - { &uid, sizeof(uid) }, - { p_data, data_length }, - { &create_flags, sizeof(create_flags) } - }; - - psa_handle_t conn = psa_connect(PSA_ITS_SET, 1); - if (conn <= PSA_NULL_HANDLE) { - return PSA_ERROR_STORAGE_FAILURE; - } - - psa_status_t status = psa_call(conn, msg, 3, NULL, 0); - if (status == PSA_DROP_CONNECTION) { - status = PSA_ERROR_STORAGE_FAILURE; - } - - psa_close(conn); - return status; -} - -psa_status_t psa_its_get(psa_storage_uid_t uid, size_t data_offset, size_t data_length, void *p_data, size_t *p_data_length) -{ - size_t actual_size = 0; - - if ((!p_data && data_length) || !p_data_length) { - return PSA_ERROR_INVALID_ARGUMENT; - } - - psa_invec msg[2] = { - { &uid, sizeof(uid) }, - { &data_offset, sizeof(data_offset) } - }; - - psa_outvec resp[2] = { - { p_data, data_length }, - { &actual_size, sizeof(actual_size) } - }; - - psa_handle_t conn = psa_connect(PSA_ITS_GET, 1); - if (conn <= PSA_NULL_HANDLE) { - return PSA_ERROR_STORAGE_FAILURE; - } - - psa_status_t status = psa_call(conn, msg, 2, resp, 2); - - *p_data_length = actual_size; - - psa_close(conn); - return status; -} - -psa_status_t psa_its_get_info(psa_storage_uid_t uid, struct psa_storage_info_t *p_info) -{ - if (!p_info) { - return PSA_ERROR_INVALID_ARGUMENT; - } - - struct psa_storage_info_t info = { 0, PSA_STORAGE_FLAG_NONE }; - psa_invec msg = { &uid, sizeof(uid) }; - psa_outvec resp = { &info, sizeof(info) }; - psa_handle_t conn = psa_connect(PSA_ITS_INFO, 1); - if (conn <= PSA_NULL_HANDLE) { - return PSA_ERROR_STORAGE_FAILURE; - } - - psa_status_t status = psa_call(conn, &msg, 1, &resp, 1); - - *p_info = info; - - if (status == PSA_DROP_CONNECTION) { - status = PSA_ERROR_STORAGE_FAILURE; - } - - psa_close(conn); - return status; -} - -psa_status_t psa_its_remove(psa_storage_uid_t uid) -{ - psa_invec msg = { &uid, sizeof(uid) }; - psa_handle_t conn = psa_connect(PSA_ITS_REMOVE, 1); - if (conn <= PSA_NULL_HANDLE) { - return PSA_ERROR_STORAGE_FAILURE; - } - - psa_status_t status = psa_call(conn, &msg, 1, NULL, 0); - if (status == PSA_DROP_CONNECTION) { - status = PSA_ERROR_STORAGE_FAILURE; - } - - psa_close(conn); - return status; -} - -psa_status_t psa_its_reset() -{ - psa_handle_t conn = psa_connect(PSA_ITS_RESET, 1); - if (conn <= PSA_NULL_HANDLE) { - return PSA_ERROR_STORAGE_FAILURE; - } - - psa_status_t status = psa_call(conn, NULL, 0, NULL, 0); - if (status == PSA_DROP_CONNECTION) { - status = PSA_ERROR_STORAGE_FAILURE; - } - - psa_close(conn); - return status; -} diff --git a/components/TARGET_PSA/services/storage/its/psa_prot_internal_storage.h b/components/TARGET_PSA/services/storage/its/psa_prot_internal_storage.h deleted file mode 100644 index b4e1a0e..0000000 --- a/components/TARGET_PSA/services/storage/its/psa_prot_internal_storage.h +++ /dev/null @@ -1,164 +0,0 @@ -/* Copyright (C) 2019, ARM Limited, All Rights Reserved - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** @file -@brief This file describes the PSA Internal Trusted Storage API -*/ - -#ifndef __PSA_INTERNAL_TRUSTED_STORAGE_H__ -#define __PSA_INTERNAL_TRUSTED_STORAGE_H__ - -#include -#include - -#include "psa/error.h" -#include "psa/storage_common.h" -#include "mbed_toolchain.h" - -#ifdef __cplusplus -extern "C" { -#endif -#define PSA_ITS_API_VERSION_MAJOR 1 /**< The major version number of the PSA ITS API. It will be incremented on significant updates that may include breaking changes */ -#define PSA_ITS_API_VERSION_MINOR 1 /**< The minor version number of the PSA ITS API. It will be incremented in small updates that are unlikely to include breaking changes */ - -// These deprecated types are still used by our PSA compliance test tools -MBED_DEPRECATED("ITS specific types should not be used") -typedef psa_status_t psa_its_status_t; - -MBED_DEPRECATED("ITS specific types should not be used") -typedef psa_storage_create_flags_t psa_its_create_flags_t; - -MBED_DEPRECATED("ITS specific types should not be used") -typedef psa_storage_uid_t psa_its_uid_t; - -MBED_DEPRECATED("ITS specific types should not be used") -#define psa_its_info_t psa_storage_info_t - -// These defines should also be deprecated -#define PSA_ITS_SUCCESS PSA_SUCCESS -#define PSA_ITS_ERROR_UID_NOT_FOUND PSA_ERROR_DOES_NOT_EXIST -#define PSA_ITS_ERROR_STORAGE_FAILURE PSA_ERROR_STORAGE_FAILURE -#define PSA_ITS_ERROR_INSUFFICIENT_SPACE PSA_ERROR_INSUFFICIENT_STORAGE -#define PSA_ITS_ERROR_OFFSET_INVALID PSA_ERROR_INVALID_ARGUMENT -#define PSA_ITS_ERROR_INCORRECT_SIZE PSA_ERROR_BUFFER_TOO_SMALL -#define PSA_ITS_ERROR_INVALID_ARGUMENTS PSA_ERROR_INVALID_ARGUMENT -#define PSA_ITS_ERROR_FLAGS_NOT_SUPPORTED PSA_ERROR_NOT_SUPPORTED -#define PSA_ITS_ERROR_WRITE_ONCE PSA_ERROR_NOT_PERMITTED -#define PSA_ITS_FLAG_WRITE_ONCE PSA_STORAGE_FLAG_WRITE_ONCE - -MBED_DEPRECATED("PS specific types should not be used") -typedef psa_status_t psa_ps_status_t; -MBED_DEPRECATED("PS specific types should not be used") -typedef psa_storage_uid_t psa_ps_uid_t; -MBED_DEPRECATED("PS specific types should not be used") -typedef psa_storage_create_flags_t psa_ps_create_flags_t; -MBED_DEPRECATED("PS specific types should not be used") -#define psa_ps_info_t psa_storage_info_t - -#define PSA_PS_SUCCESS PSA_SUCCESS -#define PSA_PS_ERROR_UID_NOT_FOUND PSA_ERROR_DOES_NOT_EXIST -#define PSA_PS_ERROR_STORAGE_FAILURE PSA_ERROR_STORAGE_FAILURE -#define PSA_PS_ERROR_INSUFFICIENT_SPACE PSA_ERROR_INSUFFICIENT_STORAGE -#define PSA_PS_ERROR_OFFSET_INVALID PSA_ERROR_INVALID_ARGUMENT -#define PSA_PS_ERROR_INCORRECT_SIZE PSA_ERROR_BUFFER_TOO_SMALL -#define PSA_PS_ERROR_INVALID_ARGUMENT PSA_ERROR_INVALID_ARGUMENT -#define PSA_PS_ERROR_FLAGS_NOT_SUPPORTED PSA_ERROR_NOT_SUPPORTED -#define PSA_PS_ERROR_WRITE_ONCE PSA_ERROR_NOT_PERMITTED -#define PSA_PS_FLAG_WRITE_ONCE PSA_STORAGE_FLAG_WRITE_ONCE - -/** - * \brief create a new or modify an existing uid/value pair - * - * \param[in] uid the identifier for the data - * \param[in] data_length The size in bytes of the data in `p_data` - * \param[in] p_data A buffer containing the data - * \param[in] create_flags The flags that the data will be stored with - * - * \return A status indicating the success/failure of the operation - - * \retval PSA_SUCCESS The operation completed successfully - * \retval PSA_ERROR_NOT_PERMITTED The operation failed because the provided `uid` value was already created with PSA_STORAGE_WRITE_ONCE_FLAG - * \retval PSA_ERROR_NOT_SUPPORTED The operation failed because one or more of the flags provided in `create_flags` is not supported or is not valid - * \retval PSA_ERROR_INSUFFICIENT_STORAGE The operation failed because there was insufficient space on the storage medium - * \retval PSA_ERROR_STORAGE_FAILURE The operation failed because the physical storage has failed (Fatal error) - * \retval PSA_ERROR_INVALID_ARGUMENTS The operation failed because one of the provided pointers(`p_data`) - * is invalid, for example is `NULL` or references memory the caller cannot access - */ -psa_status_t psa_its_set(psa_storage_uid_t uid, - size_t data_length, - const void *p_data, - psa_storage_create_flags_t create_flags); - -/** - * \brief Retrieve the value associated with a provided uid - * - * \param[in] uid The uid value - * \param[in] data_offset The starting offset of the data requested - * \param[in] data_length the amount of data requested (and the minimum allocated size of the `p_data` buffer) - * \param[out] p_data The buffer where the data will be placed upon successful completion - * \param[out] p_data_length The actual amount of data returned - - * - * \return A status indicating the success/failure of the operation - * - * \retval PSA_SUCCESS The operation completed successfully - * \retval PSA_ERROR_DOES_NOT_EXIST The operation failed because the provided `uid` value was not found in the storage - * \retval PSA_ERROR_BUFFER_TOO_SMALL The operation failed because the data associated with provided `uid` is not the same size as `data_size` - * \retval PSA_ERROR_STORAGE_FAILURE The operation failed because the physical storage has failed (Fatal error) - * \retval PSA_ERROR_INVALID_ARGUMENT The operation failed because one of the provided pointers(`p_data`, `p_data_length`) - * is invalid. For example is `NULL` or references memory the caller cannot access - */ -psa_status_t psa_its_get(psa_storage_uid_t uid, - size_t data_offset, - size_t data_length, - void *p_data, - size_t *p_data_length); - -/** - * \brief Retrieve the metadata about the provided uid - * - * \param[in] uid The uid value - * \param[out] p_info A pointer to the `psa_storage_info_t` struct that will be populated with the metadata - * - * \return A status indicating the success/failure of the operation - * - * \retval PSA_SUCCESS The operation completed successfully - * \retval PSA_ERROR_DOES_NOT_EXIST The operation failed because the provided uid value was not found in the storage - * \retval PSA_ERROR_STORAGE_FAILURE The operation failed because the physical storage has failed (Fatal error) - * \retval PSA_ERROR_INVALID_ARGUMENT The operation failed because one of the provided pointers(`p_info`) - * is invalid, for example is `NULL` or references memory the caller cannot access - */ -psa_status_t psa_its_get_info(psa_storage_uid_t uid, - struct psa_storage_info_t *p_info); - -/** - * \brief Remove the provided key and its associated data from the storage - * - * \param[in] uid The uid value - * - * \return A status indicating the success/failure of the operation - * - * \retval PSA_SUCCESS The operation completed successfully - * \retval PSA_ERROR_DOES_NOT_EXIST The operation failed because the provided key value was not found in the storage - * \retval PSA_ERROR_NOT_PERMITTED The operation failed because the provided key value was created with PSA_STORAGE_WRITE_ONCE_FLAG - * \retval PSA_ERROR_STORAGE_FAILURE The operation failed because the physical storage has failed (Fatal error) - */ -psa_status_t psa_its_remove(psa_storage_uid_t uid); - -#ifdef __cplusplus -} -#endif - -#endif // __PSA_INTERNAL_TRUSTED_STORAGE_H__ diff --git a/components/TARGET_PSA/services/storage/ps/COMPONENT_NSPE/protected_storage.cpp b/components/TARGET_PSA/services/storage/ps/COMPONENT_NSPE/protected_storage.cpp deleted file mode 100644 index 65aea41..0000000 --- a/components/TARGET_PSA/services/storage/ps/COMPONENT_NSPE/protected_storage.cpp +++ /dev/null @@ -1,173 +0,0 @@ -/* Copyright (c) 2019 ARM Limited - * - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include "KVMap.h" -#include "KVStore.h" -#include "kv_config.h" -#include "TDBStore.h" -#include "psa/protected_storage.h" -#include "psa_storage_common_impl.h" -#include "mbed_error.h" -#include "mbed_toolchain.h" - -using namespace mbed; - -#ifdef __cplusplus -extern "C" -{ -#endif - -#define STR_EXPAND(tok) #tok -#define PS_VERSION_KEY "PSA_PS_VERSION" // PS version entry identifier in TDBStore - -// Global PID for protected storage, used when calling IMPL functions -#define PSA_PS_GLOBAL_PID 1 - -static KVStore *kvstore = NULL; -static bool initialized = false; - -MBED_WEAK psa_status_t ps_version_migrate(KVStore *kvstore, - const psa_storage_version_t *old_version, const psa_storage_version_t *new_version) -{ - (void)kvstore; - (void)old_version; - (void)new_version; - return PSA_SUCCESS; -} - - -static void ps_init(void) -{ - int ret = kv_init_storage_config(); - if (ret) { - // Can only happen due to system misconfiguration. - // Thus considered as unrecoverable error for runtime. - error("Failed initializing kvstore configuration\n"); - } - KVMap &kv_map = KVMap::get_instance(); - psa_storage_version_t version = {PSA_PS_API_VERSION_MAJOR, PSA_PS_API_VERSION_MINOR}; - kvstore = kv_map.get_main_kv_instance(STR_EXPAND(MBED_CONF_STORAGE_DEFAULT_KV)); - KVStore *int_kvstore = kv_map.get_internal_kv_instance(STR_EXPAND(MBED_CONF_STORAGE_DEFAULT_KV));; - if (!kvstore || !int_kvstore) { - // Can only happen due to system misconfiguration. - // Thus considered as unrecoverable error for runtime. - error("Failed getting kvstore instance\n"); - } - - psa_storage_handle_version(kvstore, PS_VERSION_KEY, &version, ps_version_migrate); - initialized = true; -} - -// used from test only -void ps_deinit(void) -{ - kvstore = NULL; - initialized = false; -} - - -psa_status_t psa_ps_set(psa_storage_uid_t uid, size_t data_length, const void *p_data, psa_storage_create_flags_t create_flags) -{ - if (!initialized) { - ps_init(); - } - - if (create_flags & ~ - (PSA_STORAGE_FLAG_WRITE_ONCE | PSA_STORAGE_FLAG_NO_CONFIDENTIALITY | PSA_STORAGE_FLAG_NO_REPLAY_PROTECTION)) { - return PSA_ERROR_NOT_SUPPORTED; - } - - // Assume confidentiality and replay protection are set by default - uint32_t kv_create_flags = KVStore::REQUIRE_CONFIDENTIALITY_FLAG | KVStore::REQUIRE_REPLAY_PROTECTION_FLAG; - - if (create_flags & PSA_STORAGE_FLAG_NO_CONFIDENTIALITY) { - kv_create_flags &= ~KVStore::REQUIRE_CONFIDENTIALITY_FLAG; - } - if (create_flags & PSA_STORAGE_FLAG_NO_REPLAY_PROTECTION) { - kv_create_flags &= ~KVStore::REQUIRE_REPLAY_PROTECTION_FLAG; - } - if (create_flags & PSA_STORAGE_FLAG_WRITE_ONCE) { - kv_create_flags |= KVStore::WRITE_ONCE_FLAG; - } - - return psa_storage_set_impl(kvstore, PSA_PS_GLOBAL_PID, uid, data_length, p_data, kv_create_flags); -} - -psa_status_t psa_ps_get(psa_storage_uid_t uid, size_t data_offset, size_t data_length, void *p_data, size_t *p_data_length) -{ - if (!initialized) { - ps_init(); - } - - return psa_storage_get_impl(kvstore, PSA_PS_GLOBAL_PID, uid, data_offset, data_length, p_data, p_data_length); -} - -psa_status_t psa_ps_get_info(psa_storage_uid_t uid, struct psa_storage_info_t *p_info) -{ - psa_status_t ret; - uint32_t kv_get_flags; - - if (!initialized) { - ps_init(); - } - - ret = psa_storage_get_info_impl(kvstore, PSA_PS_GLOBAL_PID, uid, p_info, &kv_get_flags); - - if ((kv_get_flags & ~KVStore::REQUIRE_CONFIDENTIALITY_FLAG) == kv_get_flags) { - p_info->flags |= PSA_STORAGE_FLAG_NO_CONFIDENTIALITY; - } - if ((kv_get_flags & ~KVStore::REQUIRE_REPLAY_PROTECTION_FLAG) == kv_get_flags) { - p_info->flags |= PSA_STORAGE_FLAG_NO_REPLAY_PROTECTION; - } - - return ret; -} - -psa_status_t psa_ps_remove(psa_storage_uid_t uid) -{ - if (!initialized) { - ps_init(); - } - - return psa_storage_remove_impl(kvstore, PSA_PS_GLOBAL_PID, uid); -} - -extern "C" psa_status_t psa_ps_reset() -{ - // Do not call its_init here to avoid version check before reset - int ret = kv_init_storage_config(); - if (ret) { - // Can only happen due to system misconfiguration. - // Thus considered as unrecoverable error for runtime. - error("Failed initializing kvstore configuration\n"); - } - - KVMap &kv_map = KVMap::get_instance(); - kvstore = kv_map.get_main_kv_instance(STR_EXPAND(MBED_CONF_STORAGE_DEFAULT_KV)); - if (!kvstore) { - // Can only happen due to system misconfiguration. - // Thus considered as unrecoverable error for runtime. - error("Failed getting kvstore instance\n"); - } - - return psa_storage_reset_impl(kvstore); -} - -#ifdef __cplusplus -} -#endif