Skip to content

Commit bb3f157

Browse files
Vge0rgenordicjm
authored andcommitted
nrf_security: Add protected RAM invalidation logic
Reserve two KMU slots two store random data which are used to invalidate the protected RAM content after an operation is finished. Add a Kconfig so that that it is possible for size constrained images to provision the KMU slots before usage. Ref: NCSDK-33885 Signed-off-by: Georgios Vasilakis <[email protected]>
1 parent 4dabb1f commit bb3f157

File tree

6 files changed

+128
-3
lines changed

6 files changed

+128
-3
lines changed

doc/nrf/app_dev/device_guides/nrf54l/cryptography.rst

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,10 @@ The following table gives an overview of the KMU slots and their usage:
108108
- BL_PUBKEY_2
109109
- | Revokable firmware image key for immutable bootloader, generation 2.
110110
| ED25519 public key.
111-
* - 248-255
111+
* - 248-249
112+
- Reserved
113+
- Random bytes which invalidate the protected RAM content after an operation.
114+
* - 250-255
112115
- Reserved
113116
- --
114117

subsys/nrf_security/src/drivers/cracen/Kconfig

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,17 @@ config CRACEN_LIB_KMU
4040
help
4141
The CRACEN KMU library.
4242

43+
config CRACEN_PROVISION_PROT_RAM_INV_DATA
44+
bool "Provision protected RAM invalidation data"
45+
depends on CRACEN_LIB_KMU
46+
default y
47+
help
48+
Provision the protected RAM invalidation data in the KMU. This will generate random
49+
data and provision the reserved KMU slots with the data that will be used to invalidate
50+
the protected RAM after a key is used.
51+
When disabled the application is expected to provision the reserved KMU slots 248 and 249
52+
manually, otherwise the protected RAM keys will not be usable.
53+
4354
config CRACEN_IKG
4455
bool "Enable CRACEN IKG"
4556
default y

subsys/nrf_security/src/drivers/cracen/cracenpsa/src/cracen.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,10 @@ int cracen_init(void)
144144
goto exit;
145145
}
146146

147+
#if defined(CONFIG_CRACEN_PROVISION_PROT_RAM_INV_DATA)
148+
status = cracen_provision_prot_ram_inv_data();
149+
#endif /* CONFIG_CRACEN_PROVISION_PROT_RAM_INV_DATA */
150+
147151
exit:
148152
cracen_release();
149153

subsys/nrf_security/src/drivers/cracen/cracenpsa/src/ctr_drbg.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include <sxsymcrypt/keyref.h>
2121
#include <zephyr/kernel.h>
2222
#include <nrf_security_mutexes.h>
23+
#include <string.h>
2324

2425
#ifdef CONFIG_CRACEN_HW_VERSION_LITE
2526
#define MAX_BITS_PER_REQUEST (1 << 16) /* Cracen Lite only supports 2^16 ctr size */

subsys/nrf_security/src/drivers/cracen/cracenpsa/src/kmu.c

Lines changed: 90 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include <nrf_security_mutexes.h>
1313
#include <psa/crypto.h>
1414
#include <stdint.h>
15+
#include <string.h>
1516
#include <sxsymcrypt/internal.h>
1617
#include <hw_unique_key.h>
1718
#include <cracen_psa.h>
@@ -210,6 +211,56 @@ static psa_status_t cracen_kmu_decrypt(kmu_metadata *metadata, size_t number_of_
210211

211212
#endif /* PSA_NEED_CRACEN_KMU_ENCRYPTED_KEYS */
212213

214+
#ifdef CONFIG_CRACEN_PROVISION_PROT_RAM_INV_DATA
215+
psa_status_t cracen_provision_prot_ram_inv_data(void)
216+
{
217+
uint8_t rng_buffer[2 * CRACEN_KMU_SLOT_KEY_SIZE];
218+
bool needs_provisioning;
219+
psa_key_attributes_t key_attributes = PSA_KEY_ATTRIBUTES_INIT;
220+
psa_status_t status;
221+
int kmu_slot;
222+
223+
needs_provisioning = lib_kmu_is_slot_empty(PROTECTED_RAM_INVALIDATION_DATA_SLOT1) ||
224+
lib_kmu_is_slot_empty(PROTECTED_RAM_INVALIDATION_DATA_SLOT2);
225+
226+
if (!needs_provisioning) {
227+
return PSA_SUCCESS;
228+
}
229+
230+
status = cracen_get_random(NULL, rng_buffer, sizeof(rng_buffer));
231+
if (status != PSA_SUCCESS) {
232+
return status;
233+
}
234+
235+
/* Just use attributes which are suitable for a normal protected RAM
236+
* key so that the existed KMU provision API can be used.
237+
*/
238+
psa_set_key_usage_flags(&key_attributes, PSA_KEY_USAGE_ENCRYPT);
239+
psa_set_key_algorithm(&key_attributes, PSA_ALG_CTR);
240+
psa_set_key_type(&key_attributes, PSA_KEY_TYPE_AES);
241+
psa_set_key_bits(&key_attributes, 256);
242+
psa_set_key_lifetime(&key_attributes,
243+
PSA_KEY_LIFETIME_FROM_PERSISTENCE_AND_LOCATION(
244+
PSA_KEY_PERSISTENCE_DEFAULT, PSA_KEY_LOCATION_CRACEN_KMU));
245+
246+
/* The rng material here is 256 bits so it will occupy 2 KMU slots during
247+
* the provisioning call.
248+
*/
249+
psa_set_key_id(&key_attributes,
250+
mbedtls_svc_key_id_make(0, PSA_KEY_HANDLE_FROM_CRACEN_KMU_SLOT(
251+
CRACEN_KMU_KEY_USAGE_SCHEME_PROTECTED,
252+
PROTECTED_RAM_INVALIDATION_DATA_SLOT1)));
253+
254+
kmu_slot = CRACEN_PSA_GET_KMU_SLOT(
255+
MBEDTLS_SVC_KEY_ID_GET_KEY_ID(psa_get_key_id(&key_attributes)));
256+
257+
status = cracen_kmu_provision(&key_attributes, kmu_slot, rng_buffer, sizeof(rng_buffer));
258+
safe_memzero(rng_buffer, sizeof(rng_buffer));
259+
return status;
260+
}
261+
#endif /* CONFIG_CRACEN_PROVISION_PROT_RAM_INV_DATA */
262+
263+
213264
/* Used internally in sxsymcrypt so we use sx return codes here. */
214265
int cracen_kmu_prepare_key(const uint8_t *user_data)
215266
{
@@ -255,7 +306,30 @@ int cracen_kmu_prepare_key(const uint8_t *user_data)
255306

256307
int cracen_kmu_clean_key(const uint8_t *user_data)
257308
{
258-
(void)user_data;
309+
const kmu_opaque_key_buffer *key = (const kmu_opaque_key_buffer *)user_data;
310+
bool any_slot_empty;
311+
312+
switch (key->key_usage_scheme) {
313+
case CRACEN_KMU_KEY_USAGE_SCHEME_PROTECTED:
314+
any_slot_empty = lib_kmu_is_slot_empty(PROTECTED_RAM_INVALIDATION_DATA_SLOT1) ||
315+
lib_kmu_is_slot_empty(PROTECTED_RAM_INVALIDATION_DATA_SLOT2);
316+
if (any_slot_empty) {
317+
return SX_ERR_UNKNOWN_ERROR;
318+
}
319+
320+
if (lib_kmu_push_slot(PROTECTED_RAM_INVALIDATION_DATA_SLOT1) != LIB_KMU_SUCCESS) {
321+
return SX_ERR_UNKNOWN_ERROR;
322+
}
323+
324+
if (lib_kmu_push_slot(PROTECTED_RAM_INVALIDATION_DATA_SLOT2) != LIB_KMU_SUCCESS) {
325+
return SX_ERR_UNKNOWN_ERROR;
326+
}
327+
328+
break;
329+
default:
330+
break;
331+
}
332+
259333
safe_memzero(kmu_push_area, sizeof(kmu_push_area));
260334

261335
return SX_OK;
@@ -632,6 +706,7 @@ static psa_status_t convert_to_psa_attributes(kmu_metadata *metadata,
632706
static psa_status_t convert_from_psa_attributes(const psa_key_attributes_t *key_attr,
633707
kmu_metadata *metadata)
634708
{
709+
int kmu_slot;
635710
memset(metadata, 0, sizeof(*metadata));
636711
metadata->metadata_version = 0;
637712

@@ -790,7 +865,14 @@ static psa_status_t convert_from_psa_attributes(const psa_key_attributes_t *key_
790865
break;
791866
#endif
792867
default:
793-
return PSA_ERROR_NOT_SUPPORTED;
868+
/* Ignore the algorithm for the protected ram invalidation kmu slot because
869+
* it will never be used for crypto operations.
870+
*/
871+
kmu_slot = CRACEN_PSA_GET_KMU_SLOT(
872+
MBEDTLS_SVC_KEY_ID_GET_KEY_ID(psa_get_key_id(key_attr)));
873+
if (kmu_slot != PROTECTED_RAM_INVALIDATION_DATA_SLOT1) {
874+
return PSA_ERROR_NOT_SUPPORTED;
875+
}
794876
}
795877

796878
psa_key_usage_t resulting_usage = 0;
@@ -1070,6 +1152,12 @@ psa_status_t cracen_kmu_get_builtin_key(psa_drv_slot_number_t slot_number,
10701152
return status;
10711153
}
10721154

1155+
if (slot_number == PROTECTED_RAM_INVALIDATION_DATA_SLOT1 ||
1156+
slot_number == PROTECTED_RAM_INVALIDATION_DATA_SLOT2) {
1157+
/* The protected ram invalidation slots are not used for crypto operations. */
1158+
return PSA_ERROR_INVALID_ARGUMENT;
1159+
}
1160+
10731161
status = clean_up_unfinished_provisioning();
10741162
if (status != PSA_SUCCESS) {
10751163
return status;

subsys/nrf_security/src/drivers/cracen/cracenpsa/src/kmu.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,14 @@ typedef struct {
2727
uint8_t slot_id; /* KMU slot number. */
2828
} kmu_opaque_key_buffer;
2929

30+
/* Two KMU slots are reserved for storing the invalidation data for the protected RAM.
31+
* These are meant to have random data that can pushed to the protected RAM after
32+
* an actual key is being used so that the key material does not reside in the protected
33+
* RAM for more than the required time.
34+
*/
35+
#define PROTECTED_RAM_INVALIDATION_DATA_SLOT1 248
36+
#define PROTECTED_RAM_INVALIDATION_DATA_SLOT2 249
37+
3038
extern uint8_t kmu_push_area[64];
3139

3240
/**
@@ -65,3 +73,13 @@ psa_status_t cracen_kmu_provision(const psa_key_attributes_t *key_attr, int slot
6573
* @brief Destroy a key stored in the KMU.
6674
*/
6775
psa_status_t cracen_kmu_destroy_key(const psa_key_attributes_t *attributes);
76+
77+
/**
78+
* @brief Provision the protected RAM invalidation data.
79+
*
80+
* This function provisions two KMU slots with random data that can be used to invalidate
81+
* the protected RAM after a key is used.
82+
*
83+
* @return PSA status code.
84+
*/
85+
psa_status_t cracen_provision_prot_ram_inv_data(void);

0 commit comments

Comments
 (0)