Skip to content

Commit

Permalink
secure_storage: add a global registry header file for PSA key IDs
Browse files Browse the repository at this point in the history
We need to make sure that within Zephyr different users of the PSA APIs
don't interfere with each other because of using the same numerical IDs
for persistent assets.

This takes care of the PSA key IDs when using persistent keys through
the PSA Crypto API.
See the comments in `<zephyr/psa/key_ids.h>` for more information.

This removes the recently-introduced Kconfig options that allowed changing
the base IDs subsystems were using for their persistent keys.

Signed-off-by: Tomi Fontanilles <[email protected]>
  • Loading branch information
tomi-font authored and kartben committed Feb 13, 2025
1 parent 71d663d commit 0c368e8
Show file tree
Hide file tree
Showing 13 changed files with 103 additions and 91 deletions.
1 change: 1 addition & 0 deletions MAINTAINERS.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4341,6 +4341,7 @@ Secure storage:
- tomi-font
files:
- subsys/secure_storage/
- include/zephyr/psa/
- samples/psa/
- doc/services/secure_storage.rst
- tests/subsys/secure_storage/
Expand Down
51 changes: 51 additions & 0 deletions include/zephyr/psa/key_ids.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/* Copyright (c) 2025 Nordic Semiconductor
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ZEPHYR_PSA_KEY_IDS_H_
#define ZEPHYR_PSA_KEY_IDS_H_

/**
* @file zephyr/psa/key_ids.h
*
* @brief This file defines the key ID ranges of the existing users of the PSA Crypto API.
*
* In addition to the application, different subsystems store and use persistent keys through the
* PSA Crypto API. Because they are not aware of each other, collisions are avoided by having them
* use different ID ranges.
* This file acts as the registry of all the allocated PSA key ID ranges within Zephyr.
*
* The end-user application also has a dedicated range, `ZEPHYR_PSA_APPLICATION_KEY_ID_RANGE_BEGIN`.
*
* Some of the IDs below are based on previously existing and used values, while others
* are chosen to be somewhere in the PSA user key ID range to try to avoid collisions
* (avoiding, for example, the very beginning of the range).
*/

#include <stdint.h>
typedef uint32_t psa_key_id_t;

/** PSA key ID range to be used by OpenThread. The base ID is equal to the default value upstream:
* https://github.com/openthread/openthread/blob/thread-reference-20230706/src/core/config/platform.h#L138
*/
#define ZEPHYR_PSA_OPENTHREAD_KEY_ID_RANGE_BEGIN (psa_key_id_t)0x20000
#define ZEPHYR_PSA_OPENTHREAD_KEY_ID_RANGE_SIZE 0x10000 /* 64 Ki */

/** PSA key ID range to be used by Matter. The base ID is equal to the default value upstream:
* https://github.com/project-chip/connectedhomeip/blob/v1.4.0.0/src/crypto/CHIPCryptoPALPSA.h#L55
*/
#define ZEPHYR_PSA_MATTER_KEY_ID_RANGE_BEGIN (psa_key_id_t)0x30000
#define ZEPHYR_PSA_MATTER_KEY_ID_RANGE_SIZE 0x10000 /* 64 Ki */

/** PSA key ID range to be used by Bluetooth Mesh. */
#define ZEPHYR_PSA_BT_MESH_KEY_ID_RANGE_BEGIN (psa_key_id_t)0x20000000
#define ZEPHYR_PSA_BT_MESH_KEY_ID_RANGE_SIZE 0xC000 /* 48 Ki */

/** PSA key ID range to be used by Wi-Fi credentials management. */
#define ZEPHYR_PSA_WIFI_CREDENTIALS_KEY_ID_RANGE_BEGIN (psa_key_id_t)0x20010000
#define ZEPHYR_PSA_WIFI_CREDENTIALS_KEY_ID_RANGE_SIZE 0x100 /* 256 */

/** PSA key ID range to be used by the end-user application. */
#define ZEPHYR_PSA_APPLICATION_KEY_ID_RANGE_BEGIN (psa_key_id_t)0x30000000
#define ZEPHYR_PSA_APPLICATION_KEY_ID_RANGE_SIZE 0x100000 /* 1 Mi */

#endif /* ZEPHYR_PSA_KEY_IDS_H_ */
8 changes: 0 additions & 8 deletions modules/openthread/Kconfig.thread
Original file line number Diff line number Diff line change
Expand Up @@ -250,11 +250,3 @@ config OPENTHREAD_MLE_CHILD_TIMEOUT
default 240
help
The value of MLE child timeout in seconds.

config OPENTHREAD_PSA_ITS_NVM_OFFSET
hex "NVM offset while using key refs"
default 0x20000
help
The offset value in the PSA ITS non-volatile space is dedicated to OpenThread
key reference IDs. This offset must not overwrite any other ranges already in
use within the PSA ITS non-volatile space.
5 changes: 2 additions & 3 deletions modules/openthread/platform/openthread-core-zephyr-config.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#define OPENTHREAD_CORE_ZEPHYR_CONFIG_H_

#include <zephyr/devicetree.h>
#include <zephyr/psa/key_ids.h>
#include <zephyr/toolchain.h>

/**
Expand Down Expand Up @@ -516,8 +517,6 @@
* NVM offset while using key refs.
*
*/
#ifdef CONFIG_OPENTHREAD_PSA_ITS_NVM_OFFSET
#define OPENTHREAD_CONFIG_PSA_ITS_NVM_OFFSET CONFIG_OPENTHREAD_PSA_ITS_NVM_OFFSET
#endif
#define OPENTHREAD_CONFIG_PSA_ITS_NVM_OFFSET ZEPHYR_PSA_OPENTHREAD_KEY_ID_RANGE_BEGIN

#endif /* OPENTHREAD_CORE_ZEPHYR_CONFIG_H_ */
3 changes: 2 additions & 1 deletion samples/psa/persistent_key/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@
*/
#include <psa/crypto.h>
#include <zephyr/logging/log.h>
#include <zephyr/psa/key_ids.h>

LOG_MODULE_REGISTER(persistent_key);

#define SAMPLE_KEY_ID PSA_KEY_ID_USER_MIN
#define SAMPLE_KEY_ID ZEPHYR_PSA_APPLICATION_KEY_ID_RANGE_BEGIN
#define SAMPLE_KEY_TYPE PSA_KEY_TYPE_AES
#define SAMPLE_ALG PSA_ALG_CTR
#define SAMPLE_KEY_BITS 256
Expand Down
16 changes: 0 additions & 16 deletions subsys/bluetooth/mesh/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -1531,22 +1531,6 @@ config BT_MESH_USES_TFM_PSA

endchoice

if BT_MESH_USES_MBEDTLS_PSA || BT_MESH_USES_TFM_PSA

config BT_MESH_PSA_KEY_ID_USER_MIN_OFFSET
int "Offset of Bluetooth Mesh key id range regarding PSA_KEY_ID_USER_MIN"
default 0
help
The PSA specification mandates to set key identifiers for keys
with persistent lifetime. The users of the PSA API is responsible
(Bluetooth Mesh is user of PSA API) to provide correct and unique identifiers.
The Bluetooth Mesh identifier range should be between PSA_KEY_ID_USER_MIN and
PSA_KEY_ID_USER_MAX. Bluetooth Mesh requires two ids for each subnetwork, two ids
for each application key, and two ids for the device key and device key candidate.
It should consider the Mesh Configuration Database instances if database enabled.

endif # BT_MESH_USES_MBEDTLS_PSA || BT_MESH_USES_TFM_PSA

menu "Beacons"

config BT_MESH_BEACON_ENABLED
Expand Down
31 changes: 16 additions & 15 deletions subsys/bluetooth/mesh/crypto_psa.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <errno.h>

#include <zephyr/bluetooth/mesh.h>
#include <zephyr/psa/key_ids.h>
#include <zephyr/sys/check.h>

#define LOG_LEVEL CONFIG_BT_MESH_CRYPTO_LOG_LEVEL
Expand All @@ -26,13 +27,13 @@ LOG_MODULE_REGISTER(bt_mesh_crypto_psa);
#else
#define BT_MESH_CDB_KEY_ID_RANGE_SIZE 0
#endif
#define BT_MESH_KEY_ID_RANGE_SIZE (2 * CONFIG_BT_MESH_SUBNET_COUNT + \
2 * CONFIG_BT_MESH_APP_KEY_COUNT + 2 + BT_MESH_CDB_KEY_ID_RANGE_SIZE)
#define BT_MESH_PSA_KEY_ID_USER_MIN (PSA_KEY_ID_USER_MIN + \
CONFIG_BT_MESH_PSA_KEY_ID_USER_MIN_OFFSET)

BUILD_ASSERT(BT_MESH_PSA_KEY_ID_USER_MIN + BT_MESH_KEY_ID_RANGE_SIZE <= PSA_KEY_ID_USER_MAX,
"Bluetooth Mesh PSA key id range overlaps maximum allowed boundary.");
#define BT_MESH_PSA_KEY_ID_MIN ZEPHYR_PSA_BT_MESH_KEY_ID_RANGE_BEGIN

#define BT_MESH_PSA_KEY_ID_RANGE_SIZE (2 * CONFIG_BT_MESH_SUBNET_COUNT + \
2 * CONFIG_BT_MESH_APP_KEY_COUNT + 2 + BT_MESH_CDB_KEY_ID_RANGE_SIZE)
BUILD_ASSERT(BT_MESH_PSA_KEY_ID_RANGE_SIZE <= ZEPHYR_PSA_BT_MESH_KEY_ID_RANGE_SIZE,
"PSA key ID range exceeds officially allocated range.");

BUILD_ASSERT(PSA_MAC_LENGTH(PSA_KEY_TYPE_AES, 128, PSA_ALG_CMAC) == 16,
"MAC length should be 16 bytes for 128-bits key for CMAC-AES");
Expand All @@ -46,7 +47,7 @@ static struct {
uint8_t public_key_be[PUB_KEY_SIZE + 1];
} dh_pair;

static ATOMIC_DEFINE(pst_keys, BT_MESH_KEY_ID_RANGE_SIZE);
static ATOMIC_DEFINE(pst_keys, BT_MESH_PSA_KEY_ID_RANGE_SIZE);

int bt_mesh_crypto_init(void)
{
Expand Down Expand Up @@ -354,10 +355,10 @@ int bt_mesh_dhkey_gen(const uint8_t *pub_key, const uint8_t *priv_key, uint8_t *

__weak psa_key_id_t bt_mesh_user_keyid_alloc(void)
{
for (int i = 0; i < BT_MESH_KEY_ID_RANGE_SIZE; i++) {
for (int i = 0; i < BT_MESH_PSA_KEY_ID_RANGE_SIZE; i++) {
if (!atomic_test_bit(pst_keys, i)) {
atomic_set_bit(pst_keys, i);
return BT_MESH_PSA_KEY_ID_USER_MIN + i;
return BT_MESH_PSA_KEY_ID_MIN + i;
}
}

Expand All @@ -366,9 +367,9 @@ __weak psa_key_id_t bt_mesh_user_keyid_alloc(void)

__weak int bt_mesh_user_keyid_free(psa_key_id_t key_id)
{
if (IN_RANGE(key_id, BT_MESH_PSA_KEY_ID_USER_MIN,
BT_MESH_PSA_KEY_ID_USER_MIN + BT_MESH_KEY_ID_RANGE_SIZE - 1)) {
atomic_clear_bit(pst_keys, key_id - BT_MESH_PSA_KEY_ID_USER_MIN);
if (IN_RANGE(key_id, BT_MESH_PSA_KEY_ID_MIN,
BT_MESH_PSA_KEY_ID_MIN + BT_MESH_PSA_KEY_ID_RANGE_SIZE - 1)) {
atomic_clear_bit(pst_keys, key_id - BT_MESH_PSA_KEY_ID_MIN);
return 0;
}

Expand All @@ -377,9 +378,9 @@ __weak int bt_mesh_user_keyid_free(psa_key_id_t key_id)

__weak void bt_mesh_user_keyid_assign(psa_key_id_t key_id)
{
if (IN_RANGE(key_id, BT_MESH_PSA_KEY_ID_USER_MIN,
BT_MESH_PSA_KEY_ID_USER_MIN + BT_MESH_KEY_ID_RANGE_SIZE - 1)) {
atomic_set_bit(pst_keys, key_id - BT_MESH_PSA_KEY_ID_USER_MIN);
if (IN_RANGE(key_id, BT_MESH_PSA_KEY_ID_MIN,
BT_MESH_PSA_KEY_ID_MIN + BT_MESH_PSA_KEY_ID_RANGE_SIZE - 1)) {
atomic_set_bit(pst_keys, key_id - BT_MESH_PSA_KEY_ID_MIN);
}
}

Expand Down
12 changes: 0 additions & 12 deletions subsys/net/lib/wifi_credentials/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -75,18 +75,6 @@ endif # WIFI_CREDENTIALS_CONNECT_STORED

endif # WIFI_CREDENTIALS

if WIFI_CREDENTIALS_BACKEND_PSA

config WIFI_CREDENTIALS_BACKEND_PSA_OFFSET
int "PSA_KEY_ID range offset"
default 0
help
The PSA specification mandates to set key identifiers for keys
with persistent lifetime. The users of the PSA API are responsible (WIFI credentials
management is user of PSA API) to provide correct and unique identifiers.

endif # WIFI_CREDENTIALS_BACKEND_PSA

config WIFI_CREDENTIALS_STATIC
bool "Static Wi-Fi network configuration"

Expand Down
17 changes: 7 additions & 10 deletions subsys/net/lib/wifi_credentials/wifi_credentials_backend_psa.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,15 @@

#include <zephyr/kernel.h>
#include <zephyr/logging/log.h>
#include <zephyr/psa/key_ids.h>
#include "psa/crypto.h"

#include "wifi_credentials_internal.h"

LOG_MODULE_REGISTER(wifi_credentials_backend, CONFIG_WIFI_CREDENTIALS_LOG_LEVEL);

#define WIFI_CREDENTIALS_BACKEND_PSA_KEY_ID_USER_MIN \
(PSA_KEY_ID_USER_MIN + CONFIG_WIFI_CREDENTIALS_BACKEND_PSA_OFFSET)

BUILD_ASSERT((WIFI_CREDENTIALS_BACKEND_PSA_KEY_ID_USER_MIN + CONFIG_WIFI_CREDENTIALS_MAX_ENTRIES) <=
PSA_KEY_ID_USER_MAX,
"WIFI credentials management PSA key id range exceeds PSA_KEY_ID_USER_MAX.");
BUILD_ASSERT(CONFIG_WIFI_CREDENTIALS_MAX_ENTRIES <= ZEPHYR_PSA_WIFI_CREDENTIALS_KEY_ID_RANGE_SIZE,
"Wi-Fi credentials management PSA key ID range exceeds officially allocated range.");

int wifi_credentials_backend_init(void)
{
Expand All @@ -26,7 +23,7 @@ int wifi_credentials_backend_init(void)

for (size_t i = 0; i < CONFIG_WIFI_CREDENTIALS_MAX_ENTRIES; ++i) {
size_t length_read = 0;
size_t key_id = i + WIFI_CREDENTIALS_BACKEND_PSA_KEY_ID_USER_MIN;
size_t key_id = i + ZEPHYR_PSA_WIFI_CREDENTIALS_KEY_ID_RANGE_BEGIN;

ret = psa_export_key(key_id, buf, ARRAY_SIZE(buf), &length_read);
if (ret == PSA_SUCCESS && length_read == ENTRY_MAX_LEN) {
Expand All @@ -46,7 +43,7 @@ int wifi_credentials_store_entry(size_t idx, const void *buf, size_t buf_len)
psa_key_attributes_t key_attributes = {0};
psa_key_id_t key_id;

psa_set_key_id(&key_attributes, idx + WIFI_CREDENTIALS_BACKEND_PSA_KEY_ID_USER_MIN);
psa_set_key_id(&key_attributes, idx + ZEPHYR_PSA_WIFI_CREDENTIALS_KEY_ID_RANGE_BEGIN);
psa_set_key_usage_flags(&key_attributes, PSA_KEY_USAGE_EXPORT);
psa_set_key_lifetime(&key_attributes, PSA_KEY_LIFETIME_PERSISTENT);
psa_set_key_algorithm(&key_attributes, PSA_ALG_NONE);
Expand All @@ -67,7 +64,7 @@ int wifi_credentials_store_entry(size_t idx, const void *buf, size_t buf_len)

int wifi_credentials_delete_entry(size_t idx)
{
psa_status_t ret = psa_destroy_key(idx + WIFI_CREDENTIALS_BACKEND_PSA_KEY_ID_USER_MIN);
psa_status_t ret = psa_destroy_key(idx + ZEPHYR_PSA_WIFI_CREDENTIALS_KEY_ID_RANGE_BEGIN);

if (ret != PSA_SUCCESS) {
LOG_ERR("psa_destroy_key failed, err: %d", ret);
Expand All @@ -80,7 +77,7 @@ int wifi_credentials_delete_entry(size_t idx)
int wifi_credentials_load_entry(size_t idx, void *buf, size_t buf_len)
{
size_t length_read = 0;
size_t key_id = idx + WIFI_CREDENTIALS_BACKEND_PSA_KEY_ID_USER_MIN;
size_t key_id = idx + ZEPHYR_PSA_WIFI_CREDENTIALS_KEY_ID_RANGE_BEGIN;
psa_status_t ret;

ret = psa_export_key(key_id, buf, buf_len, &length_read);
Expand Down
32 changes: 16 additions & 16 deletions tests/bsim/bluetooth/mesh/src/distribute_keyid.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

#include <errno.h>
#include <zephyr/bluetooth/mesh.h>
#include <zephyr/psa/key_ids.h>
#include "argparse.h"
#include "mesh/crypto.h"

Expand All @@ -22,24 +23,23 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME);
#else
#define BT_MESH_CDB_KEY_ID_RANGE_SIZE 0
#endif
#define BT_MESH_KEY_ID_RANGE_SIZE (2 * CONFIG_BT_MESH_SUBNET_COUNT + \
2 * CONFIG_BT_MESH_APP_KEY_COUNT + 1 + BT_MESH_CDB_KEY_ID_RANGE_SIZE)
#define BT_MESH_PSA_KEY_ID_USER_MIN (PSA_KEY_ID_USER_MIN + \
CONFIG_BT_MESH_PSA_KEY_ID_USER_MIN_OFFSET)
#define BT_MESH_TEST_PSA_KEY_ID_USER_MIN (BT_MESH_PSA_KEY_ID_USER_MIN + \
BT_MESH_KEY_ID_RANGE_SIZE * get_device_nbr())

static ATOMIC_DEFINE(pst_keys, BT_MESH_KEY_ID_RANGE_SIZE);
#define BT_MESH_PSA_KEY_ID_RANGE_SIZE (2 * CONFIG_BT_MESH_SUBNET_COUNT + \
2 * CONFIG_BT_MESH_APP_KEY_COUNT + 2 + BT_MESH_CDB_KEY_ID_RANGE_SIZE)
#define BT_MESH_TEST_PSA_KEY_ID_MIN (ZEPHYR_PSA_BT_MESH_KEY_ID_RANGE_BEGIN + \
BT_MESH_PSA_KEY_ID_RANGE_SIZE * get_device_nbr())

static ATOMIC_DEFINE(pst_keys, BT_MESH_PSA_KEY_ID_RANGE_SIZE);

psa_key_id_t bt_mesh_user_keyid_alloc(void)
{
for (int i = 0; i < BT_MESH_KEY_ID_RANGE_SIZE; i++) {
for (int i = 0; i < BT_MESH_PSA_KEY_ID_RANGE_SIZE; i++) {
if (!atomic_test_bit(pst_keys, i)) {
atomic_set_bit(pst_keys, i);

LOG_INF("key id %d is allocated", BT_MESH_TEST_PSA_KEY_ID_USER_MIN + i);
LOG_INF("key id %d is allocated", BT_MESH_TEST_PSA_KEY_ID_MIN + i);

return BT_MESH_TEST_PSA_KEY_ID_USER_MIN + i;
return BT_MESH_TEST_PSA_KEY_ID_MIN + i;
}
}

Expand All @@ -48,9 +48,9 @@ psa_key_id_t bt_mesh_user_keyid_alloc(void)

int bt_mesh_user_keyid_free(psa_key_id_t key_id)
{
if (IN_RANGE(key_id, BT_MESH_TEST_PSA_KEY_ID_USER_MIN,
BT_MESH_TEST_PSA_KEY_ID_USER_MIN + BT_MESH_KEY_ID_RANGE_SIZE - 1)) {
atomic_clear_bit(pst_keys, key_id - BT_MESH_TEST_PSA_KEY_ID_USER_MIN);
if (IN_RANGE(key_id, BT_MESH_TEST_PSA_KEY_ID_MIN,
BT_MESH_TEST_PSA_KEY_ID_MIN + BT_MESH_PSA_KEY_ID_RANGE_SIZE - 1)) {
atomic_clear_bit(pst_keys, key_id - BT_MESH_TEST_PSA_KEY_ID_MIN);

LOG_INF("key id %d is freed", key_id);

Expand All @@ -62,9 +62,9 @@ int bt_mesh_user_keyid_free(psa_key_id_t key_id)

void bt_mesh_user_keyid_assign(psa_key_id_t key_id)
{
if (IN_RANGE(key_id, BT_MESH_TEST_PSA_KEY_ID_USER_MIN,
BT_MESH_TEST_PSA_KEY_ID_USER_MIN + BT_MESH_KEY_ID_RANGE_SIZE - 1)) {
atomic_set_bit(pst_keys, key_id - BT_MESH_TEST_PSA_KEY_ID_USER_MIN);
if (IN_RANGE(key_id, BT_MESH_TEST_PSA_KEY_ID_MIN,
BT_MESH_TEST_PSA_KEY_ID_MIN + BT_MESH_PSA_KEY_ID_RANGE_SIZE - 1)) {
atomic_set_bit(pst_keys, key_id - BT_MESH_TEST_PSA_KEY_ID_MIN);
LOG_INF("key id %d is assigned", key_id);
} else {
LOG_WRN("key id %d is out of the reserved id range", key_id);
Expand Down
1 change: 0 additions & 1 deletion tests/net/lib/wifi_credentials_backend_psa/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ target_compile_options(app
-DCONFIG_WIFI_CREDENTIALS_MAX_ENTRIES=2
-DCONFIG_WIFI_CREDENTIALS_SAE_PASSWORD_LENGTH=128
-DCONFIG_WIFI_CREDENTIALS_LOG_LEVEL=4
-DCONFIG_WIFI_CREDENTIALS_BACKEND_PSA_OFFSET=5
)

set_property(
Expand Down
Loading

0 comments on commit 0c368e8

Please sign in to comment.