From 814b2ed45704ac974f92e632c3351fccfb067e37 Mon Sep 17 00:00:00 2001 From: Valerio Setti Date: Tue, 4 Jun 2024 13:47:34 +0200 Subject: [PATCH] bt-host: add option to use PSA APIs instead of TinyCrypt By enabling CONFIG_BT_USE_PSA_API the user can specify to use PSA APIs instead of TinyCrypt for crypto operations in bluetooth host module. This commit also extends tests/bluetooth/gatt in order to add a PSA test. Signed-off-by: Valerio Setti --- subsys/bluetooth/host/CMakeLists.txt | 18 ++- subsys/bluetooth/host/Kconfig | 11 +- subsys/bluetooth/host/Kconfig.gatt | 8 +- subsys/bluetooth/host/crypto_psa.c | 151 ++++++++++++++++++ .../bluetooth/host/{crypto.c => crypto_tc.c} | 0 subsys/bluetooth/host/gatt.c | 115 +++++++++++-- tests/bluetooth/gatt/testcase.yaml | 18 +++ 7 files changed, 293 insertions(+), 28 deletions(-) create mode 100644 subsys/bluetooth/host/crypto_psa.c rename subsys/bluetooth/host/{crypto.c => crypto_tc.c} (100%) diff --git a/subsys/bluetooth/host/CMakeLists.txt b/subsys/bluetooth/host/CMakeLists.txt index 56cdfb04575..ae574e2b5bf 100644 --- a/subsys/bluetooth/host/CMakeLists.txt +++ b/subsys/bluetooth/host/CMakeLists.txt @@ -31,10 +31,13 @@ if(CONFIG_BT_HCI_HOST) CONFIG_BT_OBSERVER scan.c ) - zephyr_library_sources_ifdef( - CONFIG_BT_HOST_CRYPTO - crypto.c - ) + + if(CONFIG_BT_USE_PSA_API) + zephyr_library_sources_ifdef(CONFIG_BT_HOST_CRYPTO crypto_psa.c) + else() + zephyr_library_sources_ifdef(CONFIG_BT_HOST_CRYPTO crypto_tc.c) + endif() + zephyr_library_sources_ifdef( CONFIG_BT_ECC ecc.c @@ -108,6 +111,13 @@ if(CONFIG_BT_CONN_DISABLE_SECURITY) ) endif() +if(CONFIG_BT_USE_PSA_API) + zephyr_library_link_libraries_ifdef(CONFIG_MBEDTLS mbedTLS) + zephyr_library_include_directories_ifdef(CONFIG_BUILD_WITH_TFM + $/api_ns/interface/include + ) +endif() + # Bluetooth Mesh has test dependencies in the host. # In order to compile Bsim tests with these test features # and PSA enabled, the libraries must be linked. diff --git a/subsys/bluetooth/host/Kconfig b/subsys/bluetooth/host/Kconfig index f9bbac130cc..49277097da9 100644 --- a/subsys/bluetooth/host/Kconfig +++ b/subsys/bluetooth/host/Kconfig @@ -139,8 +139,9 @@ rsource "../audio/Kconfig" config BT_HOST_CRYPTO bool "Use crypto functionality implemented in the Bluetooth host" default y if !BT_CTLR_CRYPTO - select TINYCRYPT - select TINYCRYPT_AES + select TINYCRYPT if !BT_USE_PSA_API + select TINYCRYPT_AES if !BT_USE_PSA_API + select PSA_WANT_KEY_TYPE_AES if BT_USE_PSA_API help The option adds the AES encryption support using TinyCrypt library if this is not provided by the controller implementation. @@ -148,9 +149,9 @@ config BT_HOST_CRYPTO config BT_HOST_CRYPTO_PRNG bool "Use Tinycrypt library for random number generation" default y - select TINYCRYPT_SHA256 - select TINYCRYPT_SHA256_HMAC - select TINYCRYPT_SHA256_HMAC_PRNG + select TINYCRYPT_SHA256 if !BT_USE_PSA_API + select TINYCRYPT_SHA256_HMAC if !BT_USE_PSA_API + select TINYCRYPT_SHA256_HMAC_PRNG if !BT_USE_PSA_API depends on BT_HOST_CRYPTO help When selected, will use tinycrypt library for random number generation. diff --git a/subsys/bluetooth/host/Kconfig.gatt b/subsys/bluetooth/host/Kconfig.gatt index 310442423b9..45e3fa8e4fc 100644 --- a/subsys/bluetooth/host/Kconfig.gatt +++ b/subsys/bluetooth/host/Kconfig.gatt @@ -107,9 +107,11 @@ config BT_GATT_CACHING bool "GATT Caching support" default y depends on BT_GATT_SERVICE_CHANGED - select TINYCRYPT - select TINYCRYPT_AES - select TINYCRYPT_AES_CMAC + select TINYCRYPT if !BT_USE_PSA_API + select TINYCRYPT_AES if !BT_USE_PSA_API + select TINYCRYPT_AES_CMAC if !BT_USE_PSA_API + select PSA_WANT_KEY_TYPE_AES if BT_USE_PSA_API + select PSA_WANT_ALG_CMAC if BT_USE_PSA_API help This option enables support for GATT Caching. When enabled the stack will register Client Supported Features and Database Hash diff --git a/subsys/bluetooth/host/crypto_psa.c b/subsys/bluetooth/host/crypto_psa.c new file mode 100644 index 00000000000..041a2f9cd04 --- /dev/null +++ b/subsys/bluetooth/host/crypto_psa.c @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2017 Nordic Semiconductor ASA + * Copyright (c) 2015-2016 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include "psa/crypto.h" + +#include "common/bt_str.h" + +#include "hci_core.h" + +#define LOG_LEVEL CONFIG_BT_HCI_CORE_LOG_LEVEL +#include +LOG_MODULE_REGISTER(bt_host_crypto); + +int prng_init(void) +{ + if (psa_crypto_init() != PSA_SUCCESS) { + return -EIO; + } + return 0; +} + +#if defined(CONFIG_BT_HOST_CRYPTO_PRNG) +int bt_rand(void *buf, size_t len) +{ + if (psa_generate_random(buf, len) == PSA_SUCCESS) { + return 0; + } + + return -EIO; +} +#else /* !CONFIG_BT_HOST_CRYPTO_PRNG */ +int bt_rand(void *buf, size_t len) +{ + CHECKIF(buf == NULL || len == 0) { + return -EINVAL; + } + + return bt_hci_le_rand(buf, len); +} +#endif /* CONFIG_BT_HOST_CRYPTO_PRNG */ + +int bt_encrypt_le(const uint8_t key[16], const uint8_t plaintext[16], + uint8_t enc_data[16]) +{ + psa_key_attributes_t attr = PSA_KEY_ATTRIBUTES_INIT; + psa_key_id_t key_id = MBEDTLS_SVC_KEY_ID_INIT; + psa_status_t status, destroy_status; + size_t out_len; + uint8_t tmp[16]; + + CHECKIF(key == NULL || plaintext == NULL || enc_data == NULL) { + return -EINVAL; + } + + LOG_DBG("key %s", bt_hex(key, 16)); + LOG_DBG("plaintext %s", bt_hex(plaintext, 16)); + + sys_memcpy_swap(tmp, key, 16); + + psa_set_key_type(&attr, PSA_KEY_TYPE_AES); + psa_set_key_bits(&attr, 128); + psa_set_key_usage_flags(&attr, PSA_KEY_USAGE_ENCRYPT); + psa_set_key_algorithm(&attr, PSA_ALG_ECB_NO_PADDING); + if (psa_import_key(&attr, tmp, 16, &key_id) != PSA_SUCCESS) { + LOG_ERR("Failed to import AES key"); + return -EINVAL; + } + + sys_memcpy_swap(tmp, plaintext, 16); + + status = psa_cipher_encrypt(key_id, PSA_ALG_ECB_NO_PADDING, tmp, 16, + enc_data, 16, &out_len); + if (status != PSA_SUCCESS) { + LOG_ERR("AES encryption failed"); + } + + destroy_status = psa_destroy_key(key_id); + if (destroy_status != PSA_SUCCESS) { + LOG_ERR("Failed to destroy AES key"); + } + + if ((status != PSA_SUCCESS) || (destroy_status != PSA_SUCCESS)) { + return -EIO; + } + + sys_mem_swap(enc_data, 16); + + LOG_DBG("enc_data %s", bt_hex(enc_data, 16)); + + return 0; +} + +int bt_encrypt_be(const uint8_t key[16], const uint8_t plaintext[16], + uint8_t enc_data[16]) +{ + psa_key_attributes_t attr = PSA_KEY_ATTRIBUTES_INIT; + psa_key_id_t key_id = MBEDTLS_SVC_KEY_ID_INIT; + psa_status_t status, destroy_status; + size_t out_len; + + CHECKIF(key == NULL || plaintext == NULL || enc_data == NULL) { + return -EINVAL; + } + + LOG_DBG("key %s", bt_hex(key, 16)); + LOG_DBG("plaintext %s", bt_hex(plaintext, 16)); + + psa_set_key_type(&attr, PSA_KEY_TYPE_AES); + psa_set_key_bits(&attr, 128); + psa_set_key_usage_flags(&attr, PSA_KEY_USAGE_ENCRYPT); + psa_set_key_algorithm(&attr, PSA_ALG_ECB_NO_PADDING); + if (psa_import_key(&attr, key, 16, &key_id) != PSA_SUCCESS) { + LOG_ERR("Failed to import AES key"); + return -EINVAL; + } + + status = psa_cipher_encrypt(key_id, PSA_ALG_ECB_NO_PADDING, + plaintext, 16, enc_data, 16, &out_len); + if (status != PSA_SUCCESS) { + LOG_ERR("AES encryption failed"); + } + + destroy_status = psa_destroy_key(key_id); + if (destroy_status != PSA_SUCCESS) { + LOG_ERR("Failed to destroy AES key"); + } + + if ((status != PSA_SUCCESS) || (destroy_status != PSA_SUCCESS)) { + return -EIO; + } + + LOG_DBG("enc_data %s", bt_hex(enc_data, 16)); + + return 0; +} diff --git a/subsys/bluetooth/host/crypto.c b/subsys/bluetooth/host/crypto_tc.c similarity index 100% rename from subsys/bluetooth/host/crypto.c rename to subsys/bluetooth/host/crypto_tc.c diff --git a/subsys/bluetooth/host/gatt.c b/subsys/bluetooth/host/gatt.c index 6a967f9672a..19c71087b42 100644 --- a/subsys/bluetooth/host/gatt.c +++ b/subsys/bluetooth/host/gatt.c @@ -21,11 +21,15 @@ #include #if defined(CONFIG_BT_GATT_CACHING) +#if defined(CONFIG_BT_USE_PSA_API) +#include "psa/crypto.h" +#else /* CONFIG_BT_USE_PSA_API */ #include #include #include #include #include +#endif /* CONFIG_BT_USE_PSA_API */ #endif /* CONFIG_BT_GATT_CACHING */ #include @@ -693,11 +697,93 @@ static ssize_t cf_write(struct bt_conn *conn, const struct bt_gatt_attr *attr, return len; } +#if defined(CONFIG_BT_USE_PSA_API) struct gen_hash_state { - struct tc_cmac_struct state; + psa_mac_operation_t operation; + psa_key_id_t key; int err; }; +static int db_hash_setup(struct gen_hash_state *state, uint8_t *key) +{ + psa_key_attributes_t key_attr = PSA_KEY_ATTRIBUTES_INIT; + + psa_set_key_type(&key_attr, PSA_KEY_TYPE_AES); + psa_set_key_bits(&key_attr, 128); + psa_set_key_usage_flags(&key_attr, PSA_KEY_USAGE_SIGN_MESSAGE); + psa_set_key_algorithm(&key_attr, PSA_ALG_CMAC); + + if (psa_import_key(&key_attr, key, 16, &(state->key)) != PSA_SUCCESS) { + LOG_ERR("Unable to import the key for AES CMAC"); + return -EIO; + } + state->operation = psa_mac_operation_init(); + if (psa_mac_sign_setup(&(state->operation), state->key, + PSA_ALG_CMAC) != PSA_SUCCESS) { + LOG_ERR("CMAC operation init failed"); + return -EIO; + } + return 0; +} + +static int db_hash_update(struct gen_hash_state *state, uint8_t *data, size_t len) +{ + if (psa_mac_update(&(state->operation), data, len) != PSA_SUCCESS) { + LOG_ERR("CMAC update failed"); + return -EIO; + } + return 0; +} + +static int db_hash_finish(struct gen_hash_state *state) +{ + size_t mac_length; + + if (psa_mac_sign_finish(&(state->operation), db_hash.hash, 16, + &mac_length) != PSA_SUCCESS) { + LOG_ERR("CMAC finish failed"); + return -EIO; + } + return 0; +} + +#else /* CONFIG_BT_USE_PSA_API */ +struct gen_hash_state { + struct tc_cmac_struct state; + struct tc_aes_key_sched_struct sched; + int err; +}; + +static int db_hash_setup(struct gen_hash_state *state, uint8_t *key) +{ + if (tc_cmac_setup(&(state->state), key, &(state->sched)) == TC_CRYPTO_FAIL) { + LOG_ERR("CMAC setup failed"); + return -EIO; + } + return 0; +} + +static int db_hash_update(struct gen_hash_state *state, uint8_t *data, size_t len) +{ + if (tc_cmac_update(&state->state, data, len) == TC_CRYPTO_FAIL) { + LOG_ERR("CMAC update failed"); + return -EIO; + } + return 0; +} + +static int db_hash_finish(struct gen_hash_state *state) +{ + if (tc_cmac_final(db_hash.hash, &(state->state)) == TC_CRYPTO_FAIL) { + LOG_ERR("CMAC finish failed"); + return -EIO; + } + return 0; +} + + +#endif /* CONFIG_BT_USE_PSA_API */ + union hash_attr_value { /* Bluetooth Core Specification Version 5.3 | Vol 3, Part G * Table 3.1: Service declaration @@ -755,15 +841,15 @@ static uint8_t gen_hash_m(const struct bt_gatt_attr *attr, uint16_t handle, case BT_UUID_GATT_CHRC_VAL: case BT_UUID_GATT_CEP_VAL: value = sys_cpu_to_le16(handle); - if (tc_cmac_update(&state->state, (uint8_t *)&value, - sizeof(handle)) == TC_CRYPTO_FAIL) { + if (db_hash_update(state, (uint8_t *)&value, + sizeof(handle)) != 0) { state->err = -EINVAL; return BT_GATT_ITER_STOP; } value = sys_cpu_to_le16(u16->val); - if (tc_cmac_update(&state->state, (uint8_t *)&value, - sizeof(u16->val)) == TC_CRYPTO_FAIL) { + if (db_hash_update(state, (uint8_t *)&value, + sizeof(u16->val)) != 0) { state->err = -EINVAL; return BT_GATT_ITER_STOP; } @@ -774,8 +860,7 @@ static uint8_t gen_hash_m(const struct bt_gatt_attr *attr, uint16_t handle, return BT_GATT_ITER_STOP; } - if (tc_cmac_update(&state->state, data, len) == - TC_CRYPTO_FAIL) { + if (db_hash_update(state, data, len) != 0) { state->err = -EINVAL; return BT_GATT_ITER_STOP; } @@ -788,18 +873,19 @@ static uint8_t gen_hash_m(const struct bt_gatt_attr *attr, uint16_t handle, case BT_UUID_GATT_CPF_VAL: case BT_UUID_GATT_CAF_VAL: value = sys_cpu_to_le16(handle); - if (tc_cmac_update(&state->state, (uint8_t *)&value, - sizeof(handle)) == TC_CRYPTO_FAIL) { + if (db_hash_update(state, (uint8_t *)&value, + sizeof(handle)) != 0) { state->err = -EINVAL; return BT_GATT_ITER_STOP; } value = sys_cpu_to_le16(u16->val); - if (tc_cmac_update(&state->state, (uint8_t *)&value, - sizeof(u16->val)) == TC_CRYPTO_FAIL) { + if (db_hash_update(state, (uint8_t *)&value, + sizeof(u16->val)) != 0) { state->err = -EINVAL; return BT_GATT_ITER_STOP; } + break; default: return BT_GATT_ITER_CONTINUE; @@ -825,18 +911,15 @@ static void db_hash_store(void) static void db_hash_gen(void) { uint8_t key[16] = {}; - struct tc_aes_key_sched_struct sched; struct gen_hash_state state; - if (tc_cmac_setup(&state.state, key, &sched) == TC_CRYPTO_FAIL) { - LOG_ERR("Unable to setup AES CMAC"); + if (db_hash_setup(&state, key) != 0) { return; } bt_gatt_foreach_attr(0x0001, 0xffff, gen_hash_m, &state); - if (tc_cmac_final(db_hash.hash, &state.state) == TC_CRYPTO_FAIL) { - LOG_ERR("Unable to calculate hash"); + if (db_hash_finish(&state) != 0) { return; } diff --git a/tests/bluetooth/gatt/testcase.yaml b/tests/bluetooth/gatt/testcase.yaml index 135f6d823ed..fd349d00f52 100644 --- a/tests/bluetooth/gatt/testcase.yaml +++ b/tests/bluetooth/gatt/testcase.yaml @@ -14,3 +14,21 @@ tests: tags: - bluetooth - gatt + bluetooth.gatt.psa: + filter: CONFIG_PSA_CRYPTO_CLIENT + extra_args: + - EXTRA_DTC_OVERLAY_FILE="test.overlay" + platform_allow: + - native_posix + - native_posix/native/64 + - native_sim + - native_sim/native/64 + - qemu_x86 + - qemu_cortex_m3 + - nrf5340dk/nrf5340/cpuapp/ns + - nrf52840dk/nrf52840 + integration_platforms: + - native_sim + tags: + - bluetooth + - gatt