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:
Tomi Fontanilles 2024-09-13 09:32:18 +03:00 committed by Carles Cufí
parent d6bee54986
commit c9a59dd02d
8 changed files with 258 additions and 0 deletions

View File

@ -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)

View File

@ -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>`_

View File

@ -0,0 +1,4 @@
# SPDX-License-Identifier: Apache-2.0
CONFIG_ENTROPY_GENERATOR=y
CONFIG_MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG=y

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

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