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 <vsetti@baylibre.com>
This commit is contained in:
Valerio Setti 2024-06-04 13:47:34 +02:00 committed by Alberto Escolar
commit 814b2ed457
7 changed files with 293 additions and 28 deletions

View file

@ -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
$<TARGET_PROPERTY:tfm,TFM_BINARY_DIR>/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.

View file

@ -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.

View file

@ -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

View file

@ -0,0 +1,151 @@
/*
* Copyright (c) 2017 Nordic Semiconductor ASA
* Copyright (c) 2015-2016 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include <errno.h>
#include <zephyr/kernel.h>
#include <zephyr/sys/byteorder.h>
#include <zephyr/sys/check.h>
#include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/bluetooth/hci.h>
#include <zephyr/bluetooth/conn.h>
#include <zephyr/bluetooth/crypto.h>
#include "psa/crypto.h"
#include "common/bt_str.h"
#include "hci_core.h"
#define LOG_LEVEL CONFIG_BT_HCI_CORE_LOG_LEVEL
#include <zephyr/logging/log.h>
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;
}

View file

@ -21,11 +21,15 @@
#include <zephyr/settings/settings.h>
#if defined(CONFIG_BT_GATT_CACHING)
#if defined(CONFIG_BT_USE_PSA_API)
#include "psa/crypto.h"
#else /* CONFIG_BT_USE_PSA_API */
#include <tinycrypt/constants.h>
#include <tinycrypt/utils.h>
#include <tinycrypt/aes.h>
#include <tinycrypt/cmac_mode.h>
#include <tinycrypt/ccm_mode.h>
#endif /* CONFIG_BT_USE_PSA_API */
#endif /* CONFIG_BT_GATT_CACHING */
#include <zephyr/bluetooth/hci.h>
@ -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;
}

View file

@ -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