Skip to content

Commit

Permalink
lib: hw_unique_key: Remove k_panic and return error
Browse files Browse the repository at this point in the history
The hardware unique key library until now panicked with k_panic
in case of error in most of the cases. It is a preferred
practice to return error codes and let the application
decide what to do with the error. This updates the functions
from void to int and adds some extra error codes to cover
all the cases.

Ref: NCSDK-21839

Signed-off-by: Georgios Vasilakis <georgios.vasilakis@nordicsemi.no>
  • Loading branch information
Vge0rge committed Jun 22, 2023
1 parent 01f4531 commit c8ccbcc
Show file tree
Hide file tree
Showing 13 changed files with 131 additions and 63 deletions.
9 changes: 9 additions & 0 deletions doc/nrf/releases/release-notes-changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,15 @@ Other libraries
* :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

/** @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
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;

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;
}

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;
}
18 changes: 10 additions & 8 deletions lib/hw_unique_key/hw_unique_key_kmu.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,28 +49,30 @@ static int write_slot(enum hw_unique_key_slot kmu_slot, uint32_t target_addr, co
NRF_CC3XX_PLATFORM_KMU_DEFAULT_PERMISSIONS, key);
}

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)
{
int err = write_slot(kmu_slot, NRF_CC3XX_PLATFORM_KMU_AES_ADDR, key);
int err = write_slot(key_slot, NRF_CC3XX_PLATFORM_KMU_AES_ADDR, key);

#ifdef HUK_HAS_CC312
if (err == 0) {
err = write_slot(kmu_slot + 1, NRF_CC3XX_PLATFORM_KMU_AES_ADDR_2,
err = write_slot(key_slot + 1, NRF_CC3XX_PLATFORM_KMU_AES_ADDR_2,
key + (HUK_SIZE_BYTES / 2));
}
#endif

if (err != 0) {
printk("The HUK writing to: %d failed with error code: %d\r\n", kmu_slot, err);
k_panic();
printk("The HUK writing to: %d failed with error code: %d\r\n", key_slot, err);
return -HW_UNIQUE_KEY_ERR_WRITE_FAILED;
}

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)
{
#ifdef HUK_HAS_CC312
return key_written(kmu_slot) || key_written(kmu_slot + 1);
return key_written(key_slot) || key_written(key_slot + 1);
#else
return key_written(kmu_slot);
return key_written(key_slot);
#endif
}
6 changes: 3 additions & 3 deletions modules/tfm/tfm/boards/common/crypto_keys.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,10 @@ static enum tfm_plat_err_t tfm_plat_get_huk(uint8_t *buf, size_t buf_len,

uint8_t label[] = "TFM_HW_UNIQ_KEY";

int err = hw_unique_key_derive_key(HUK_KEYSLOT_MEXT, NULL,
0, label, sizeof(label), buf, buf_len);
int err = hw_unique_key_derive_key(HUK_KEYSLOT_MEXT, NULL, 0, label, sizeof(label), buf,
buf_len);

if (err) {
if (err != HW_UNIQUE_KEY_SUCCESS) {
SPMLOG_DBGMSGVAL("hw_unique_key_derive_key err: ", err);

return TFM_PLAT_ERR_SYSTEM_ERR;
Expand Down
6 changes: 5 additions & 1 deletion modules/tfm/tfm/boards/common/tfm_hal_platform.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,11 @@ static enum tfm_hal_status_t crypto_platform_init(void)
!defined(PLATFORM_DEFAULT_CRYPTO_KEYS)
if (!hw_unique_key_are_any_written()) {
SPMLOG_INFMSG("Writing random Hardware Unique Keys to the KMU.\r\n");
hw_unique_key_write_random();
err = hw_unique_key_write_random();
if (err != HW_UNIQUE_KEY_SUCCESS) {
SPMLOG_DBGMSGVAL("hw_unique_key_write_random failed with error code:", err);
return TFM_HAL_ERROR_BAD_STATE;
}
SPMLOG_INFMSG("Success\r\n");
}
#endif
Expand Down
6 changes: 5 additions & 1 deletion samples/bootloader/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,11 @@ int load_huk(void)

}

hw_unique_key_load_kdr();
if (hw_unique_key_load_kdr() != HW_UNIQUE_KEY_SUCCESS) {
printk("Error: Cannot load the Hardware Unique Key into the KDR.\n");
k_panic();
return -1;
}

return 0;
}
Expand Down
2 changes: 1 addition & 1 deletion samples/keys/hw_unique_key/src/derive_key.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ psa_key_id_t derive_key(psa_key_attributes_t *attributes, uint8_t *key_label,

int result = hw_unique_key_derive_key(KEYSLOT, NULL, 0,
key_label, label_size, key_out, sizeof(key_out));
if (result != 0) {
if (result != HW_UNIQUE_KEY_SUCCESS) {
printk("hw_unique_key_derive_key returned error: %d\n", result);
return 0;
}
Expand Down
6 changes: 5 additions & 1 deletion samples/keys/hw_unique_key/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,11 @@ int main(void)

if (!hw_unique_key_are_any_written()) {
printk("Writing random keys to KMU\n");
hw_unique_key_write_random();
result = hw_unique_key_write_random();
if (result != HW_UNIQUE_KEY_SUCCESS) {
printk("hw_unique_key_write_random returned error: %d\n", result);
return 0;
}
printk("Success!\n\n");

#if !defined(HUK_HAS_KMU)
Expand Down
Loading

0 comments on commit c8ccbcc

Please sign in to comment.