samples: psa: persistent_key: add the persistent_key sample
Add a sample to demonstrate use of persistent keys in the PSA Crypto API. The implementation of the PSA ITS API that allows storage of persistent keys is provided either by the just-introduced secure storage subsystem or by TF-M. Signed-off-by: Tomi Fontanilles <tomi.fontanilles@nordicsemi.no>
This commit is contained in:
parent
d6bee54986
commit
c9a59dd02d
|
@ -0,0 +1,7 @@
|
|||
# SPDX-License-Identifier: Apache-2.0
|
||||
cmake_minimum_required(VERSION 3.20.0)
|
||||
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
|
||||
|
||||
project(persistent_key)
|
||||
|
||||
target_sources(app PRIVATE src/main.c)
|
|
@ -0,0 +1,70 @@
|
|||
.. zephyr:code-sample:: persistent_key
|
||||
:name: PSA Crypto persistent key
|
||||
|
||||
Manage and use persistent keys via the PSA Crypto API.
|
||||
|
||||
Overview
|
||||
********
|
||||
|
||||
This sample demonstrates usage of persistent keys in the :ref:`PSA Crypto API <psa_crypto>`.
|
||||
|
||||
Requirements
|
||||
************
|
||||
|
||||
In addition to the PSA Crypto API, an implementation of the
|
||||
`PSA Internal Trusted Storage (ITS) API <https://arm-software.github.io/psa-api/storage/1.0/overview/architecture.html#the-internal-trusted-storage-api>`_
|
||||
(for storage of the persistent keys) must be present for this sample to work.
|
||||
It can be provided by:
|
||||
|
||||
* :ref:`tfm`, for ``*/ns`` :term:`board targets<board target>`.
|
||||
* The :ref:`secure storage subsystem <secure_storage>`, for the other board targets.
|
||||
|
||||
Building
|
||||
********
|
||||
|
||||
This sample is located in :zephyr_file:`samples/psa/persistent_key`.
|
||||
|
||||
Different configurations are defined in the :file:`sample.yaml` file.
|
||||
You can use them to build the sample, depending on the PSA ITS provider, as follows:
|
||||
|
||||
.. tabs::
|
||||
|
||||
.. tab:: TF-M
|
||||
|
||||
For board targets with TF-M:
|
||||
|
||||
.. zephyr-app-commands::
|
||||
:zephyr-app: samples/psa/persistent_key
|
||||
:tool: west
|
||||
:goals: build
|
||||
:board: <ns_board_target>
|
||||
:west-args: -T sample.psa.persistent_key.tfm
|
||||
|
||||
.. tab:: secure storage subsystem
|
||||
|
||||
For board targets without TF-M.
|
||||
|
||||
If the board target to compile for has an entropy driver (preferable):
|
||||
|
||||
.. zephyr-app-commands::
|
||||
:zephyr-app: samples/psa/persistent_key
|
||||
:tool: west
|
||||
:goals: build
|
||||
:board: <board_target>
|
||||
:west-args: -T sample.psa.persistent_key.secure_storage.entropy_driver
|
||||
|
||||
Or, to use an insecure entropy source (only for testing):
|
||||
|
||||
.. zephyr-app-commands::
|
||||
:zephyr-app: samples/psa/persistent_key
|
||||
:tool: west
|
||||
:goals: build
|
||||
:board: <board_target>
|
||||
:west-args: -T sample.psa.persistent_key.secure_storage.entropy_not_secure
|
||||
|
||||
To flash it, see :ref:`west-flashing`.
|
||||
|
||||
API reference
|
||||
*************
|
||||
|
||||
`PSA Crypto key management API reference <https://arm-software.github.io/psa-api/crypto/1.2/api/keys/index.html>`_
|
|
@ -0,0 +1,4 @@
|
|||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
CONFIG_ENTROPY_GENERATOR=y
|
||||
CONFIG_MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG=y
|
|
@ -0,0 +1,5 @@
|
|||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
CONFIG_TEST_RANDOM_GENERATOR=y
|
||||
CONFIG_TIMER_RANDOM_GENERATOR=y
|
||||
CONFIG_MBEDTLS_ENTROPY_POLL_ZEPHYR=y
|
|
@ -0,0 +1,10 @@
|
|||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
CONFIG_MBEDTLS=y
|
||||
CONFIG_MBEDTLS_PSA_CRYPTO_C=y
|
||||
|
||||
# The default stack size (1024) is not enough for the PSA Crypto core.
|
||||
# On top of that, the ITS implementation uses the stack for buffers.
|
||||
CONFIG_MAIN_STACK_SIZE=3072
|
||||
|
||||
CONFIG_SECURE_STORAGE=y
|
|
@ -0,0 +1,8 @@
|
|||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
CONFIG_LOG=y
|
||||
CONFIG_LOG_DEFAULT_LEVEL=3
|
||||
CONFIG_ASSERT=y
|
||||
|
||||
CONFIG_PSA_WANT_KEY_TYPE_AES=y
|
||||
CONFIG_PSA_WANT_ALG_CTR=y
|
|
@ -0,0 +1,31 @@
|
|||
sample:
|
||||
name: PSA Crypto persistent key sample
|
||||
description: Demonstration of persistent key usage in the PSA Crypto API.
|
||||
common:
|
||||
tags:
|
||||
- psa.secure_storage
|
||||
timeout: 10
|
||||
harness: console
|
||||
harness_config:
|
||||
type: one_line
|
||||
regex:
|
||||
- "Sample finished successfully."
|
||||
tests:
|
||||
sample.psa.persistent_key.tfm:
|
||||
filter: CONFIG_BUILD_WITH_TFM
|
||||
tags:
|
||||
- trusted-firmware-m
|
||||
sample.psa.persistent_key.secure_storage.entropy_driver:
|
||||
filter: CONFIG_SECURE_STORAGE and not CONFIG_SECURE_STORAGE_ITS_STORE_IMPLEMENTATION_NONE
|
||||
and CONFIG_ENTROPY_HAS_DRIVER
|
||||
extra_args: EXTRA_CONF_FILE=overlay-secure_storage.conf;overlay-entropy_driver.conf
|
||||
tags:
|
||||
- drivers.entropy
|
||||
- settings
|
||||
sample.psa.persistent_key.secure_storage.entropy_not_secure:
|
||||
filter: CONFIG_SECURE_STORAGE and not CONFIG_SECURE_STORAGE_ITS_STORE_IMPLEMENTATION_NONE
|
||||
and not CONFIG_ENTROPY_HAS_DRIVER
|
||||
extra_args: EXTRA_CONF_FILE="overlay-secure_storage.conf;overlay-entropy_not_secure.conf"
|
||||
tags:
|
||||
- random
|
||||
- settings
|
|
@ -0,0 +1,123 @@
|
|||
/* Copyright (c) 2024 Nordic Semiconductor
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <psa/crypto.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
|
||||
LOG_MODULE_REGISTER(persistent_key);
|
||||
|
||||
#define SAMPLE_KEY_ID PSA_KEY_ID_USER_MIN
|
||||
#define SAMPLE_KEY_TYPE PSA_KEY_TYPE_AES
|
||||
#define SAMPLE_ALG PSA_ALG_CTR
|
||||
#define SAMPLE_KEY_BITS 256
|
||||
|
||||
int generate_persistent_key(void)
|
||||
{
|
||||
LOG_INF("Generating a persistent key...");
|
||||
psa_status_t ret;
|
||||
psa_key_id_t key_id;
|
||||
psa_key_attributes_t key_attributes = PSA_KEY_ATTRIBUTES_INIT;
|
||||
|
||||
psa_set_key_lifetime(&key_attributes, PSA_KEY_LIFETIME_PERSISTENT);
|
||||
psa_set_key_usage_flags(&key_attributes, PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT);
|
||||
psa_set_key_id(&key_attributes, SAMPLE_KEY_ID);
|
||||
psa_set_key_type(&key_attributes, SAMPLE_KEY_TYPE);
|
||||
psa_set_key_algorithm(&key_attributes, SAMPLE_ALG);
|
||||
psa_set_key_bits(&key_attributes, SAMPLE_KEY_BITS);
|
||||
|
||||
ret = psa_generate_key(&key_attributes, &key_id);
|
||||
if (ret != PSA_SUCCESS) {
|
||||
LOG_ERR("Failed to generate the key. (%d)", ret);
|
||||
return -1;
|
||||
}
|
||||
__ASSERT_NO_MSG(key_id == SAMPLE_KEY_ID);
|
||||
|
||||
/* Purge the key from volatile memory. Has the same affect than resetting the device. */
|
||||
ret = psa_purge_key(SAMPLE_KEY_ID);
|
||||
if (ret != PSA_SUCCESS) {
|
||||
LOG_ERR("Failed to purge the generated key from volatile memory. (%d).", ret);
|
||||
return -1;
|
||||
}
|
||||
|
||||
LOG_INF("Persistent key generated.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int use_persistent_key(void)
|
||||
{
|
||||
LOG_INF("Using the persistent key to encrypt and decrypt some plaintext...");
|
||||
psa_status_t ret;
|
||||
size_t ciphertext_len;
|
||||
size_t decrypted_text_len;
|
||||
|
||||
static uint8_t plaintext[] =
|
||||
"Example plaintext to demonstrate basic usage of a persistent key.";
|
||||
static uint8_t ciphertext[PSA_CIPHER_ENCRYPT_OUTPUT_SIZE(SAMPLE_KEY_TYPE, SAMPLE_ALG,
|
||||
sizeof(plaintext))];
|
||||
static uint8_t decrypted_text[sizeof(plaintext)];
|
||||
|
||||
ret = psa_cipher_encrypt(SAMPLE_KEY_ID, SAMPLE_ALG, plaintext, sizeof(plaintext),
|
||||
ciphertext, sizeof(ciphertext), &ciphertext_len);
|
||||
if (ret != PSA_SUCCESS) {
|
||||
LOG_ERR("Failed to encrypt the plaintext. (%d)", ret);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = psa_cipher_decrypt(SAMPLE_KEY_ID, SAMPLE_ALG, ciphertext, ciphertext_len,
|
||||
decrypted_text, sizeof(decrypted_text), &decrypted_text_len);
|
||||
if (ret != PSA_SUCCESS) {
|
||||
LOG_ERR("Failed to decrypt the ciphertext. (%d)", ret);
|
||||
return -1;
|
||||
}
|
||||
__ASSERT_NO_MSG(decrypted_text_len == sizeof(plaintext));
|
||||
|
||||
/* Make sure the decryption gives us the original plaintext back. */
|
||||
if (memcmp(plaintext, decrypted_text, sizeof(plaintext))) {
|
||||
LOG_HEXDUMP_INF(plaintext, sizeof(plaintext), "Plaintext:");
|
||||
LOG_HEXDUMP_INF(ciphertext, ciphertext_len, "Ciphertext:");
|
||||
LOG_HEXDUMP_INF(decrypted_text, sizeof(decrypted_text), "Decrypted text:");
|
||||
LOG_ERR("The decrypted text doesn't match the plaintext.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
LOG_INF("Persistent key usage successful.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int destroy_persistent_key(void)
|
||||
{
|
||||
LOG_INF("Destroying the persistent key...");
|
||||
psa_status_t ret;
|
||||
|
||||
ret = psa_destroy_key(SAMPLE_KEY_ID);
|
||||
if (ret != PSA_SUCCESS) {
|
||||
LOG_ERR("Failed to destroy the key. (%d)", ret);
|
||||
return -1;
|
||||
}
|
||||
|
||||
LOG_INF("Persistent key destroyed.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
LOG_INF("Persistent key sample started.");
|
||||
|
||||
/* Ensure there is not already a key with this ID. */
|
||||
psa_destroy_key(SAMPLE_KEY_ID);
|
||||
|
||||
if (generate_persistent_key()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (use_persistent_key()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (destroy_persistent_key()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
LOG_INF("Sample finished successfully.");
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue