Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ list(APPEND cracen_driver_sources
${CMAKE_CURRENT_LIST_DIR}/src/prng_pool.c
)

if(BUILD_INSIDE_TFM)
list(APPEND cracen_driver_sources
${CMAKE_CURRENT_LIST_DIR}/src/cracen_builtin_key_policy.c
)
endif()

# Include hardware cipher implementation for all devices except nRF54LM20A
# nRF54LM20A uses only cracen_sw
if(NOT CONFIG_CRACEN_NEED_MULTIPART_WORKAROUNDS)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,6 @@
#include "cracen_psa_key_ids.h"
#include "sxsymcrypt/keyref.h"

#ifdef __NRF_TFM__
#include <tfm_builtin_key_loader.h>
#endif

/**
* See "PSA Cryptography API" for documentation.
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* Copyright (c) 2025 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
*/

#ifndef CRACEN_BUILTIN_KEY_POLICY_H
#define CRACEN_BUILTIN_KEY_POLICY_H
Comment on lines +7 to +8
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

header guard mismatch


#include "common.h"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
#include "common.h"
#include <common.h>

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is this even including?

#include <psa/crypto.h>
#include <psa/crypto_values.h>

#if defined(__NRF_TFM__)

typedef struct {
mbedtls_key_owner_id_t user;
psa_drv_slot_number_t key_slot;
} cracen_builtin_ikg_key_policy_t;

typedef enum {
KMU_ENTRY_SLOT_SINGLE,
KMU_ENTRY_SLOT_RANGE,
} cracen_kmu_entry_type_t;

/* When defining a range of KMU slots both the start and end slot numbers are inclusive. */
typedef struct {
mbedtls_key_owner_id_t user;
psa_drv_slot_number_t key_slot_start;
psa_drv_slot_number_t key_slot_end;
cracen_kmu_entry_type_t kmu_entry_type;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems to me this field is not actually useful and we could just do with key_slot_start and key_slot_end alone? For the KMU_ENTRY_SLOT_SINGLE case you would just have key_slot_start == key_slot_end.

} cracen_builtin_kmu_key_policy_t;

bool cracen_builtin_key_user_allowed(const psa_key_attributes_t *attributes);

#else

static inline bool cracen_builtin_key_user_allowed(const psa_key_attributes_t *attributes)
{
(void)attributes;
return true;
}

#endif /* __NRF_TFM__ */

#endif /* CRACEN_BUILTIN_KEY_POLICY_H */

Check warning on line 46 in subsys/nrf_security/src/drivers/cracen/cracenpsa/include/cracen_psa_builtin_key_policy.h

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

MISSING_EOF_NEWLINE

subsys/nrf_security/src/drivers/cracen/cracenpsa/include/cracen_psa_builtin_key_policy.h:46 adding a line without newline at end of file
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't call this source file cracen to follow convention in this directory?

Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
/*
* Copyright (c) 2025 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
*/

#include "common.h"

#include <psa/crypto.h>
#include <psa/crypto_values.h>
#include <stddef.h>
#include <string.h>

#include "psa_manifest/pid.h"
#include "tfm_builtin_key_ids.h"
Comment on lines +14 to +15
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use angle brackets

#include <cracen_psa_builtin_key_policy.h>

#define NUMBER_OF_ELEMENTS_OF(x) (sizeof(x) / sizeof(*(x)))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is basically ARRAY_SIZE(), can you either use it if possible or if not redefine it in a header file?


#define MAPPED_TZ_NS_AGENT_DEFAULT_CLIENT_ID (-0x3c000000)

const cracen_builtin_ikg_key_policy_t g_builtin_ikg_policy[] = {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use static

#ifdef TFM_SP_ITS
{.user = TFM_SP_ITS, .key_slot = TFM_BUILTIN_KEY_ID_HUK},
#endif /* TFM_SP_ITS */
#ifdef TFM_SP_PS
{.user = TFM_SP_PS, .key_slot = TFM_BUILTIN_KEY_ID_HUK},
#endif /* TFM_SP_PS */
#ifdef TFM_SP_INITIAL_ATTESTATION
{.user = TFM_SP_INITIAL_ATTESTATION, .key_slot = TFM_BUILTIN_KEY_ID_IAK}
#endif /* TFM_SP_INITIAL_ATTESTATION */
};

#ifdef PSA_NEED_CRACEN_KMU_DRIVER

const cracen_builtin_kmu_key_policy_t g_builtin_kmu_policy[] = {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here too

/* 0x0 is used by libraries like the hw_unique_key library when manually generating psa
* key_ids. Allow access to all slots for these libraries since they don't have the logic to
* have an owner id and reside inside TF-M.
*/
{.user = 0x0,
.key_slot_start = 0,
.key_slot_end = 255,
.kmu_entry_type = KMU_ENTRY_SLOT_RANGE},
#ifdef TFM_SP_ITS
{.user = TFM_SP_ITS,
.key_slot_start = 0,
.key_slot_end = 255,
.kmu_entry_type = KMU_ENTRY_SLOT_RANGE},
#endif /* TFM_SP_ITS */
#ifdef TFM_SP_CRYPTO
{.user = TFM_SP_CRYPTO,
.key_slot_start = 0,
.key_slot_end = 255,
.kmu_entry_type = KMU_ENTRY_SLOT_RANGE},
#endif /* TFM_SP_CRYPTO */
/* The docs have KMU slots >= 180 reserved so don't allow NS users to access them */
{.user = MAPPED_TZ_NS_AGENT_DEFAULT_CLIENT_ID,
.key_slot_start = 0,
.key_slot_end = 179,
.kmu_entry_type = KMU_ENTRY_SLOT_RANGE}};

static bool cracen_builtin_kmu_user_allowed(mbedtls_key_owner_id_t owner,
psa_drv_slot_number_t slot_number,
const psa_key_attributes_t *attributes)
{
for (uint32_t i = 0; i < NUMBER_OF_ELEMENTS_OF(g_builtin_kmu_policy); i++) {

switch (g_builtin_kmu_policy[i].kmu_entry_type) {
case KMU_ENTRY_SLOT_SINGLE:
if (g_builtin_kmu_policy[i].user == owner &&
g_builtin_kmu_policy[i].key_slot_start == slot_number) {
return true;
}
break;

case KMU_ENTRY_SLOT_RANGE:
if (g_builtin_kmu_policy[i].user == owner &&
(slot_number >= g_builtin_kmu_policy[i].key_slot_start &&
slot_number <= g_builtin_kmu_policy[i].key_slot_end)) {
return true;
}
break;
default:
break;
}
}

return false;
}
#endif /* PSA_NEED_CRACEN_KMU_DRIVER */

static bool cracen_builtin_ikg_user_allowed(mbedtls_key_owner_id_t owner,
psa_drv_slot_number_t slot_number,
const psa_key_attributes_t *attributes)
{
for (uint32_t i = 0; i < NUMBER_OF_ELEMENTS_OF(g_builtin_ikg_policy); i++) {
if (g_builtin_ikg_policy[i].user == owner &&
g_builtin_ikg_policy[i].key_slot == slot_number) {
Comment on lines +98 to +99
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Terminology is not aligned (user/owner, key_slot/slot_number). Maybe align?

return true;
}
}

return false;
}

bool cracen_builtin_key_user_allowed(const psa_key_attributes_t *attributes)
{
mbedtls_key_owner_id_t owner = MBEDTLS_SVC_KEY_ID_GET_OWNER_ID(psa_get_key_id(attributes));
psa_drv_slot_number_t slot_id;
Comment on lines +109 to +110
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could also have a variable which holds MBEDTLS_SVC_KEY_ID_GET_KEY_ID(psa_get_key_id(attributes)) to avoid repetition.


if (PSA_KEY_LIFETIME_GET_LOCATION(psa_get_key_lifetime(attributes)) ==
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use a switch instead?

PSA_KEY_LOCATION_CRACEN) {

slot_id = MBEDTLS_SVC_KEY_ID_GET_KEY_ID(psa_get_key_id(attributes));
if (!cracen_builtin_ikg_user_allowed(owner, slot_id, attributes)) {
Copy link

Copilot AI Nov 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The logic here always returns false if the IKG check fails, but should return true if the check passes to allow the key operation. The early return on line 117 prevents the function from returning true when access is allowed for IKG keys. This should be: if (cracen_builtin_ikg_user_allowed(owner, slot_id, attributes)) { return true; }

Suggested change
if (!cracen_builtin_ikg_user_allowed(owner, slot_id, attributes)) {
if (cracen_builtin_ikg_user_allowed(owner, slot_id, attributes)) {
return true;
} else {

Copilot uses AI. Check for mistakes.
return false;
}
Comment on lines +116 to +118
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about just

Suggested change
if (!cracen_builtin_ikg_user_allowed(owner, slot_id, attributes)) {
return false;
}
return cracen_builtin_ikg_user_allowed(owner, slot_id, attributes)

?

}

#ifdef PSA_NEED_CRACEN_KMU_DRIVER
if (PSA_KEY_LIFETIME_GET_LOCATION(psa_get_key_lifetime(attributes)) ==
PSA_KEY_LOCATION_CRACEN_KMU) {

slot_id = CRACEN_PSA_GET_KMU_SLOT(
MBEDTLS_SVC_KEY_ID_GET_KEY_ID(psa_get_key_id(attributes)));
if (!cracen_builtin_kmu_user_allowed(owner, slot_id, attributes)) {
return false;
}
Comment on lines +125 to +129
Copy link

Copilot AI Nov 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The logic here always returns false if the KMU check fails, but should return true if the check passes. The early return on line 128 prevents the function from returning true when access is allowed for KMU keys. This should be: if (cracen_builtin_kmu_user_allowed(owner, slot_id, attributes)) { return true; }

Copilot uses AI. Check for mistakes.
}
#endif /* PSA_NEED_CRACEN_KMU_DRIVER */

return true;
}

Check warning on line 134 in subsys/nrf_security/src/drivers/cracen/cracenpsa/src/cracen_builtin_key_policy.c

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

MISSING_EOF_NEWLINE

subsys/nrf_security/src/drivers/cracen/cracenpsa/src/cracen_builtin_key_policy.c:134 adding a line without newline at end of file
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include <cracen_psa_montgomery.h>
#include <cracen_psa_ikg.h>
#include <cracen_psa_rsa_keygen.h>
#include <cracen_psa_builtin_key_policy.h>
#include <nrf_security_mutexes.h>
#include "ecc.h"
#include <silexpk/sxops/rsa.h>
Expand Down Expand Up @@ -894,6 +895,10 @@ psa_status_t cracen_export_public_key(const psa_key_attributes_t *attributes,
return PSA_ERROR_INVALID_ARGUMENT;
}

if (!cracen_builtin_key_user_allowed(attributes)) {
return PSA_ERROR_NOT_PERMITTED;
}

if (IS_ENABLED(PSA_NEED_CRACEN_KEY_TYPE_ECC_KEY_PAIR_EXPORT)) {
if (PSA_KEY_TYPE_IS_ECC_KEY_PAIR(key_type)) {
return export_ecc_public_key_from_keypair(attributes, key_buffer,
Expand Down Expand Up @@ -945,6 +950,10 @@ psa_status_t cracen_import_key(const psa_key_attributes_t *attributes, const uin
return PSA_ERROR_INVALID_ARGUMENT;
}

if (!cracen_builtin_key_user_allowed(attributes)) {
return PSA_ERROR_NOT_PERMITTED;
}

psa_key_location_t location =
PSA_KEY_LIFETIME_GET_LOCATION(psa_get_key_lifetime(attributes));
#ifdef PSA_NEED_CRACEN_KMU_DRIVER
Expand Down Expand Up @@ -1198,6 +1207,10 @@ psa_status_t cracen_generate_key(const psa_key_attributes_t *attributes, uint8_t
psa_key_location_t location =
PSA_KEY_LIFETIME_GET_LOCATION(psa_get_key_lifetime(attributes));

if (!cracen_builtin_key_user_allowed(attributes)) {
return PSA_ERROR_NOT_PERMITTED;
}

#ifdef PSA_NEED_CRACEN_KMU_DRIVER
if (location == PSA_KEY_LOCATION_CRACEN_KMU) {
return generate_key_for_kmu(attributes, key_buffer, key_buffer_size,
Expand Down Expand Up @@ -1330,6 +1343,11 @@ psa_status_t cracen_get_builtin_key(psa_drv_slot_number_t slot_number,
* and the `lifetime` field of the attribute struct. We will fill all the other
* attributes, and update the `lifetime` field to be more specific.
*/

if (!cracen_builtin_key_user_allowed(attributes)) {
return PSA_ERROR_NOT_PERMITTED;
}

switch (slot_number) {
case CRACEN_BUILTIN_IDENTITY_KEY_ID:
case CRACEN_BUILTIN_MKEK_ID:
Expand Down Expand Up @@ -1387,6 +1405,10 @@ psa_status_t cracen_export_key(const psa_key_attributes_t *attributes, const uin
psa_key_location_t location =
PSA_KEY_LIFETIME_GET_LOCATION(psa_get_key_lifetime(attributes));

if (!cracen_builtin_key_user_allowed(attributes)) {
return PSA_ERROR_NOT_PERMITTED;
}

if (location == PSA_KEY_LOCATION_CRACEN_KMU) {
/* The keys will already be in the key buffer as they got loaded their by a previous
* call to cracen_get_builtin_key or cached in the memory.
Expand Down Expand Up @@ -1435,6 +1457,10 @@ psa_status_t cracen_copy_key(psa_key_attributes_t *attributes, const uint8_t *so
size_t target_key_buffer_size, size_t *target_key_buffer_length)
{
#ifdef PSA_NEED_CRACEN_KMU_DRIVER
if (!cracen_builtin_key_user_allowed(attributes)) {
return PSA_ERROR_NOT_PERMITTED;
}

psa_key_location_t location =
PSA_KEY_LIFETIME_GET_LOCATION(psa_get_key_lifetime(attributes));

Expand Down Expand Up @@ -1489,6 +1515,10 @@ psa_status_t cracen_copy_key(psa_key_attributes_t *attributes, const uint8_t *so
psa_status_t cracen_destroy_key(const psa_key_attributes_t *attributes)
{
#ifdef PSA_NEED_CRACEN_KMU_DRIVER
if (!cracen_builtin_key_user_allowed(attributes)) {
return PSA_ERROR_NOT_PERMITTED;
}

return cracen_kmu_destroy_key(attributes);
#endif

Expand All @@ -1501,6 +1531,10 @@ psa_status_t cracen_derive_key(const psa_key_attributes_t *attributes, const uin
{
psa_key_type_t key_type = psa_get_key_type(attributes);

if (!cracen_builtin_key_user_allowed(attributes)) {
return PSA_ERROR_NOT_PERMITTED;
}

if (PSA_KEY_TYPE_IS_SPAKE2P_KEY_PAIR(key_type) && IS_ENABLED(PSA_NEED_CRACEN_SPAKE2P)) {
return cracen_derive_spake2p_key(attributes, input, input_length, key, key_size,
key_length);
Expand Down
Loading