Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

lib: Update identity_key and hw_uniq_key libraries to return error codes #11557

Merged
merged 3 commits into from
Jun 23, 2023
Merged
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
20 changes: 18 additions & 2 deletions doc/nrf/releases/release-notes-changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,8 @@ Wi-Fi samples
Other samples
-------------

|no_changes_yet_note|
* Removed the random hardware unique key sample.
The sample is redundant since its functionality is presented as part of the :ref:`hw_unique_key_usage` sample.

Drivers
=======
Expand Down Expand Up @@ -386,7 +387,22 @@ Nordic Security Module
Other libraries
---------------

|no_changes_yet_note|
* :ref:`lib_identity_key` library:

* Updated:

* :c:func:`identity_key_write_random`, :c:func:`identity_key_write_key` and :c:func:`identity_key_write_dummy` functions to return an error code and not panic on error.
* :c:func:`identity_key_read` function to always return an error code from the library-defined codes.
* The defined error code names with prefix IDENTITY_KEY_ERR_*.

* :ref:`lib_hw_unique_key` library:

* Updated:

* :c:func:`hw_unique_key_write`, :c:func:`hw_unique_key_write_random` and :c:func:`hw_unique_key_load_kdr` functions to return an error code and not panic on error.
* :c:func:`hw_unique_key_derive_key` function to always return an error code from the library-defined codes.
* The defined error code names with prefix HW_UNIQUE_KEY_ERR_*.


Common Application Framework (CAF)
----------------------------------
Expand Down
47 changes: 32 additions & 15 deletions include/hw_unique_key.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,24 @@ extern "C" {
#endif

#define HUK_SIZE_BYTES (HUK_SIZE_WORDS * 4)
#define ERR_HUK_MISSING 0x15500
Vge0rge marked this conversation as resolved.
Show resolved Hide resolved

/** @brief Error value when the hardware unique key is missing */
#define HW_UNIQUE_KEY_ERR_MISSING (0x16501)

/** @brief Error value when writing the hardware unique key failed */
#define HW_UNIQUE_KEY_ERR_WRITE_FAILED (0x16502)

/** @brief Error value when the generation of the hardware unique key failed */
#define HW_UNIQUE_KEY_ERR_GENERATION_FAILED (0x16503)

/** @brief Error value when key derivation using the hardware unique key failed */
#define HW_UNIQUE_KEY_ERR_DERIVE_FAILED (0x16504)

/** @brief Error value when the hardware unique key had a generic failure */
#define HW_UNIQUE_KEY_ERR_GENERIC_ERROR (0x16505)

/** @brief Return code for success */
#define HW_UNIQUE_KEY_SUCCESS (0x0)

/* The available slots. KDR is always available, while the MKEK and MEXT
* keys are only stored when there is a KMU, since without a key, the key
Expand All @@ -70,29 +86,31 @@ enum hw_unique_key_slot {
*
* @details This can only be done once (until a mass erase happens).
* This function waits for the flash operation to finish before returning.
* Panic on failure.
*
* @param[in] kmu_slot The keyslot to write to, see HUK_KEYSLOT_*.
* @param[in] key_slot The keyslot to write to, see HUK_KEYSLOT_*.
* @param[in] key The key to write. Must be @ref HUK_SIZE_BYTES bytes long.
*
* @return HW_UNIQUE_KEY_SUCCESS on success, otherwise a negative hardware unique key error code
*/
void hw_unique_key_write(enum hw_unique_key_slot kmu_slot, const uint8_t *key);
int hw_unique_key_write(enum hw_unique_key_slot key_slot, const uint8_t *key);

/**
* @brief Read random numbers from nrf_cc3xx_platform_ctr_drbg_get
* and write them to all slots with @ref hw_unique_key_write.
* Panic on failure.
*
* @return HW_UNIQUE_KEY_SUCCESS on success, otherwise a negative hardware unique key error code
*/
void hw_unique_key_write_random(void);
int hw_unique_key_write_random(void);

/**
* @brief Check whether a Hardware Unique Key has been written to the KMU.
*
* @param[in] kmu_slot The keyslot to check, see HUK_KEYSLOT_*.
* @param[in] key_slot The keyslot to check, see HUK_KEYSLOT_*.
*
* @retval true if a HUK has been written to the specified keyslot,
* @retval false otherwise.
*/
bool hw_unique_key_is_written(enum hw_unique_key_slot kmu_slot);
bool hw_unique_key_is_written(enum hw_unique_key_slot key_slot);

/**
* @brief Check whether any Hardware Unique Keys are written to the KMU.
Expand All @@ -108,28 +126,27 @@ bool hw_unique_key_are_any_written(void);
*
* @details It also locks the flash page which contains the key material from
* reading and writing until the next reboot.
* Panic on failure.
*
* @return HW_UNIQUE_KEY_SUCCESS on success, otherwise a negative hardware unique key error code
*/
void hw_unique_key_load_kdr(void);
int hw_unique_key_load_kdr(void);

/**
* @brief Derive a key from the specified HUK, using the nrf_cc3xx_platform API
*
* See nrf_cc3xx_platform_kmu_shadow_key_derive() for more info.
*
* @param[in] kmu_slot Keyslot to derive from.
* @param[in] key_slot Keyslot to derive from.
* @param[in] context Context for key derivation.
* @param[in] context_size Size of context.
* @param[in] label Label for key derivation.
* @param[in] label_size Size of label.
* @param[out] output The derived key.
* @param[in] output_size Size of output.
*
* @retval 0 on success
* @retval -ERR_HUK_MISSING if the slot has not been written.
* @return otherwise, an error from nrf_cc3xx_platform_kmu_shadow_key_derive()
* @return HW_UNIQUE_KEY_SUCCESS on success, otherwise a negative hardware unique key error code
*/
int hw_unique_key_derive_key(enum hw_unique_key_slot kmu_slot,
int hw_unique_key_derive_key(enum hw_unique_key_slot key_slot,
const uint8_t *context, size_t context_size,
uint8_t const *label, size_t label_size,
uint8_t *output, uint32_t output_size);
Expand Down
33 changes: 21 additions & 12 deletions include/identity_key.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,22 @@ extern "C" {
#define IDENTITY_KEY_SIZE_BYTES (32)

/** @brief Error value when MKEK is missing from the KMU */
#define ERR_IDENTITY_KEY_MKEK_MISSING (0x15501)
#define IDENTITY_KEY_ERR_MKEK_MISSING (0x15501)
Vge0rge marked this conversation as resolved.
Show resolved Hide resolved

/** @brief Error value when identity key is missing from the KMU */
#define ERR_IDENTITY_KEY_MISSING (0x15502)
#define IDENTITY_KEY_ERR_MISSING (0x15502)

/** @brief Error value when identity key can't be read */
#define ERR_IDENTITY_KEY_READ_FAILED (0x15503)
#define IDENTITY_KEY_ERR_READ_FAILED (0x15503)

/** @brief Error value when identity key can't be written */
#define IDENTITY_KEY_ERR_WRITE_FAILED (0x15504)

/** @brief Error value when identity key generation failed */
#define IDENTITY_KEY_ERR_GENERATION_FAILED (0x15505)

/** @brief Return code for success */
#define IDENTITY_KEY_SUCCESS (0x0)

/**
* @brief Function to check that the MKEK is present
Expand All @@ -58,7 +67,7 @@ bool identity_key_is_written(void);
*
* @param key Buffer to hold the decrypted identity key
*
* @return Zero on success, otherwise a non-zero error code
* @return IDENTITY_KEY_SUCCESS on success, otherwise a negative identity key error code
*/
int identity_key_read(uint8_t key[IDENTITY_KEY_SIZE_BYTES]);

Expand All @@ -67,12 +76,12 @@ int identity_key_read(uint8_t key[IDENTITY_KEY_SIZE_BYTES]);
*
* The identity key will be encrypted using the Master Key Encryption Key (MKEK).
*
* @note A panic-function that does not return will be called on write-failure.
*
* @note This function is generally only used in provisioning of the device
* and hence is not part of the code running on the end-product.
*
* @return IDENTITY_KEY_SUCCESS on success, otherwise a negative identity key error code
*/
void identity_key_write_random(void);
int identity_key_write_random(void);

/**
* @brief Function to write a previously generated identity key to the KMU
Expand All @@ -82,12 +91,12 @@ void identity_key_write_random(void);
* This function can be used in a scheme where the key is securely provisioned to
* the device in production.
*
* @note A panic-function that does not return will be called on write-failure.
*
* @note This function is generally only used in provisioning of the device
* and hence is not part of the code running on the end-product.
*
* @return IDENTITY_KEY_SUCCESS on success, otherwise a negative identity key error code
*/
void identity_key_write_key(uint8_t key[IDENTITY_KEY_SIZE_BYTES]);
int identity_key_write_key(uint8_t key[IDENTITY_KEY_SIZE_BYTES]);

/**
* @brief Function to write a dummy identity key to KMU
Expand All @@ -97,9 +106,9 @@ void identity_key_write_key(uint8_t key[IDENTITY_KEY_SIZE_BYTES]);
* @warning The dummy identity key is must only be used for debugging and testing purposes.
* Never use this function in production!
*
* @note A panic-function that does not return will be called on write-failure.
* @return IDENTITY_KEY_SUCCESS on success, otherwise a negative identity key error code
*/
void identity_key_write_dummy(void);
int identity_key_write_dummy(void);

#ifdef __cplusplus
}
Expand Down
47 changes: 30 additions & 17 deletions lib/hw_unique_key/hw_unique_key.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@


#ifdef CONFIG_HW_UNIQUE_KEY_RANDOM
void hw_unique_key_write_random(void)
int hw_unique_key_write_random(void)
{
uint8_t rand_bytes[HUK_SIZE_BYTES * ARRAY_SIZE(huk_slots)];
uint8_t zeros[sizeof(rand_bytes)] = {0};
Expand All @@ -25,45 +25,50 @@ void hw_unique_key_write_random(void)

if (hw_unique_key_are_any_written()) {
printk("One or more keys already set. Cannot overwrite\r\n");
k_panic();
return -HW_UNIQUE_KEY_ERR_WRITE_FAILED;
}

err = nrf_cc3xx_platform_ctr_drbg_init(&ctx, pers_str, sizeof(pers_str) - 1);
if (err != 0) {
printk("The RNG setup failed with error code: %d\r\n", err);
k_panic();
return -HW_UNIQUE_KEY_ERR_GENERATION_FAILED;
}

err = nrf_cc3xx_platform_ctr_drbg_get(&ctx, rand_bytes, sizeof(rand_bytes), &olen);
err2 = nrf_cc3xx_platform_ctr_drbg_free(&ctx);

if (err != 0 || olen != sizeof(rand_bytes)) {
printk("The RNG call failed with error code: %d or wrong size %d\r\n", err, olen);
k_panic();
return -HW_UNIQUE_KEY_ERR_GENERATION_FAILED;
}

if (err2 != 0) {
printk("Could not free nrf_cc3xx_platform_ctr_drbg context: %d\r\n", err2);
k_panic();
return -HW_UNIQUE_KEY_ERR_GENERATION_FAILED;
}

for (int i = 0; i < ARRAY_SIZE(huk_slots); i++) {
hw_unique_key_write(huk_slots[i], rand_bytes + (HUK_SIZE_BYTES * i));
err = hw_unique_key_write(huk_slots[i], rand_bytes + (HUK_SIZE_BYTES * i));
if (err != HW_UNIQUE_KEY_SUCCESS) {
return err;
}
}

memset(rand_bytes, 0, sizeof(rand_bytes));

if (memcmp(rand_bytes, zeros, sizeof(rand_bytes)) != 0) {
printk("The key bytes weren't correctly deleted from RAM.\r\n");
k_panic();
return -HW_UNIQUE_KEY_ERR_GENERATION_FAILED;
}

for (int i = 0; i < ARRAY_SIZE(huk_slots); i++) {
if (!hw_unique_key_is_written(huk_slots[i])) {
printk("One or more keys not set correctly\r\n");
k_panic();
return -HW_UNIQUE_KEY_ERR_WRITE_FAILED;
}
}

return HW_UNIQUE_KEY_SUCCESS;
}
#endif /* CONFIG_HW_UNIQUE_KEY_RANDOM */

Expand All @@ -77,16 +82,24 @@ bool hw_unique_key_are_any_written(void)
return false;
}

int hw_unique_key_derive_key(enum hw_unique_key_slot kmu_slot,
const uint8_t *context, size_t context_size,
uint8_t const *label, size_t label_size,
uint8_t *output, uint32_t output_size)
int hw_unique_key_derive_key(enum hw_unique_key_slot key_slot, const uint8_t *context,
size_t context_size, uint8_t const *label, size_t label_size,
uint8_t *output, uint32_t output_size)
{
if (!hw_unique_key_is_written(kmu_slot)) {
return -ERR_HUK_MISSING;
int err;
joerchan marked this conversation as resolved.
Show resolved Hide resolved

if (!hw_unique_key_is_written(key_slot)) {
return -HW_UNIQUE_KEY_ERR_MISSING;
}

return nrf_cc3xx_platform_kmu_shadow_key_derive(
kmu_slot, HUK_SIZE_BYTES * 8,
label, label_size, context, context_size, output, output_size);
err = nrf_cc3xx_platform_kmu_shadow_key_derive(key_slot, HUK_SIZE_BYTES * 8, label,
label_size, context, context_size, output,
output_size);
if (err != 0) {
printk("nrf_cc3xx_platform_kmu_shadow_key_derive failed with error code: %d\r\n",
err);
return -HW_UNIQUE_KEY_ERR_DERIVE_FAILED;
};

return HW_UNIQUE_KEY_SUCCESS;
}
28 changes: 16 additions & 12 deletions lib/hw_unique_key/hw_unique_key_acl.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@ static const uint32_t huk_magic[4] = {

static uint32_t huk_addr = PM_HW_UNIQUE_KEY_PARTITION_ADDRESS;

void hw_unique_key_write(enum hw_unique_key_slot kmu_slot, const uint8_t *key)
int hw_unique_key_write(enum hw_unique_key_slot key_slot, const uint8_t *key)
{
if (kmu_slot != HUK_KEYSLOT_KDR) {
printk("KMU slot must be HUK_KEYSLOT_KDR on nRF52840\r\n");
k_panic();
if (key_slot != HUK_KEYSLOT_KDR) {
printk("Key slot must be HUK_KEYSLOT_KDR on nRF52840\r\n");
return -HW_UNIQUE_KEY_ERR_WRITE_FAILED;
}

nrfx_nvmc_words_write(huk_addr, huk_magic, sizeof(huk_magic)/4);
Expand All @@ -34,13 +34,15 @@ void hw_unique_key_write(enum hw_unique_key_slot kmu_slot, const uint8_t *key)
nrfx_nvmc_words_write(huk_addr + sizeof(huk_magic), key, HUK_SIZE_WORDS);
while (!nrfx_nvmc_write_done_check())
;

return HW_UNIQUE_KEY_SUCCESS;
}

bool hw_unique_key_is_written(enum hw_unique_key_slot kmu_slot)
bool hw_unique_key_is_written(enum hw_unique_key_slot key_slot)
{
if (kmu_slot != HUK_KEYSLOT_KDR) {
printk("KMU slot must be HUK_KEYSLOT_KDR on nRF52840\r\n");
k_panic();
if (key_slot != HUK_KEYSLOT_KDR) {
printk("Key slot must be HUK_KEYSLOT_KDR on nRF52840\r\n");
return false;
joerchan marked this conversation as resolved.
Show resolved Hide resolved
}

uint32_t protection = fprotect_is_protected(huk_addr);
Expand All @@ -60,27 +62,29 @@ bool hw_unique_key_is_written(enum hw_unique_key_slot kmu_slot)
return false;
}

void hw_unique_key_load_kdr(void)
int hw_unique_key_load_kdr(void)
{
int err = -1;

/* Compare the huk_magic data with the content of the page */
if (memcmp((uint8_t *)huk_addr, huk_magic, sizeof(huk_magic) != 0)) {
printk("Could not load the HUK, magic data is not present\r\n");
k_panic();
return -HW_UNIQUE_KEY_ERR_MISSING;
}

err = nrf_cc3xx_platform_kdr_load_key((uint8_t *)huk_addr +
sizeof(huk_magic));
if (err != 0) {
printk("The HUK loading failed with error code: %d\r\n", err);
k_panic();
return -HW_UNIQUE_KEY_ERR_GENERIC_ERROR;
}

/* Lock the flash page which holds the key */
err = fprotect_area_no_access(huk_addr, CONFIG_FPROTECT_BLOCK_SIZE);
if (err != 0) {
printk("Fprotect failed with error code: %d\r\n", err);
k_panic();
return -HW_UNIQUE_KEY_ERR_GENERIC_ERROR;
}

return HW_UNIQUE_KEY_SUCCESS;
}
Loading