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

sys/psa_crypto: Implement persistent key storage #20099

Merged
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
4 changes: 4 additions & 0 deletions sys/include/psa_crypto/psa/crypto.h
Original file line number Diff line number Diff line change
Expand Up @@ -895,7 +895,7 @@
size_t *output_length);
#endif /* MODULE_PSA_ASYMMETRIC */


Check warning on line 898 in sys/include/psa_crypto/psa/crypto.h

View workflow job for this annotation

GitHub Actions / static-tests

too many consecutive empty lines
#if IS_USED(MODULE_PSA_CIPHER) || defined(DOXYGEN)
/**
* @brief Abort a cipher operation.
Expand Down Expand Up @@ -1503,6 +1503,10 @@
* If a key is currently in use in a multi-part operation, then destroying the key will
* cause the multi-part operation to fail.
*
* @warning This implementation uses a virtual file system for storing and reading persistent keys
* to and from flash. Destroying a key only unlinks the file and does not erase the actual
* key data from flash. Anyone with hardware access can still recover the key material.
*
* @param key Identifier of the key to erase. If this is @ref PSA_KEY_ID_NULL, do nothing and
* return @ref PSA_SUCCESS.
*
Expand Down Expand Up @@ -4075,4 +4079,4 @@
#endif

#endif /* PSA_CRYPTO_PSA_CRYPTO_H */
/** @} */

Check warning on line 4082 in sys/include/psa_crypto/psa/crypto.h

View workflow job for this annotation

GitHub Actions / static-tests

source file is too long
4 changes: 4 additions & 0 deletions sys/psa_crypto/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ ifneq (,$(filter psa_key_slot_mgmt,$(USEMODULE)))
DIRS += psa_key_slot_mgmt
endif

ifneq (,$(filter psa_persistent_storage,$(USEMODULE)))
DIRS += psa_persistent_storage
endif

ifneq (,$(filter psa_se_mgmt,$(USEMODULE)))
DIRS += psa_se_mgmt
endif
Expand Down
9 changes: 9 additions & 0 deletions sys/psa_crypto/Makefile.dep
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,15 @@ ifneq (,$(filter psa_crypto,$(USEMODULE)))
USEMODULE += prng_sha256prng
endif

ifneq (,$(filter psa_persistent_storage, $(USEMODULE)))
USEPKG += nanocbor
USEPKG += littlefs2
USEMODULE += vfs
USEMODULE += vfs_default
USEMODULE += vfs_auto_format
USEMODULE += vfs_auto_mount
endif

# Asymmetric
ifneq (,$(filter psa_asymmetric,$(USEMODULE)))
USEMODULE += psa_key_management
Expand Down
17 changes: 15 additions & 2 deletions sys/psa_crypto/doc.txt
Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,13 @@
* Persistent keys will also be written into flash memory for later access. To destroy
* them they must be explicitly deleted with the `psa_destroy_key()` function.
*
* @note So far this implementation only supports volatile storage. Persistent storage
* will be added in the future.
* @note Persistent key storage can be optionally enabled on `native` and on the `nRF52840dk`.
* For this, add `USEMODULE += psa_persistent_storage` to your application makefile
* or `CONFIG_MODULE_PSA_PERSISTENT_STORAGE=y` to your `app.config.test` file.
* Example: `tests/sys/psa_crypto_persistent_storage`
mguetschow marked this conversation as resolved.
Show resolved Hide resolved
*
* @warning Be aware that the current implementation writes keys in plain text to flash memory.
* Anyone with hardware access can read them.
*
* #### Lifetime Encoding
* When creating a key, the user needs to specify a lifetime value, which actually consists
Expand Down Expand Up @@ -220,6 +225,11 @@
* CFLAGS += -DCONFIG_PSA_PROTECTED_KEY_COUNT=2
* @endcode
*
* @note The key slot count defines the maximum number of keys that can be cached in
* RAM at runtime. It does not limit the number of persistent keys that can be stored
* in flash memory. It is the user's responsibility to keep track of the number of
* persistently stored keys.
*
* ## Available Modules {#available-modules}
* Below are the currently available modules.
* No matter which operation you need, you always have to choose the base module.
Expand All @@ -233,6 +243,9 @@
* When using `app.config.test` files in your application directory, you need to write the
* names in uppercase and add the prefix `CONFIG_MODULE_` to all of them.
*
* ### Key Storage
* - Persistent Key Storage: psa_persistent_storage
*
* ### Asymmetric Crypto
* - Base: psa_asymmetric
*
Expand Down
149 changes: 149 additions & 0 deletions sys/psa_crypto/include/psa_crypto_cbor_encoder.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
/*
* Copyright (C) 2023 HAW Hamburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/

/**
* @ingroup sys_psa_crypto
* @defgroup sys_psa_crypto_cbor_encoder Module for encoding PSA keys in CBOR
* @{
*
* @file psa_crypto_cbor_encoder.h
* @brief
*
* @author Lena Boeckmann <[email protected]>
*
*/

#ifndef PSA_CRYPTO_CBOR_ENCODER_H
#define PSA_CRYPTO_CBOR_ENCODER_H

#ifdef __cplusplus
extern "C" {
#endif

#include "psa_crypto_slot_management.h"

/**
* @brief Required size of CBOR output buffer from start to end of attributes.
* Adds attributes sizes to CBOR encodings for individual values.
*/
#define CBOR_BUF_SIZE_START ( 1 + /* Array encoding */ \
1 + /* Array encoding */ \
1 + sizeof(psa_key_id_t) + \
1 + sizeof(psa_key_type_t) + \
1 + sizeof(psa_key_bits_t) + \
1 + sizeof(psa_key_lifetime_t) + \
1 + /* Array encoding */ \
1 + sizeof(psa_key_usage_t) + \
1 + sizeof(psa_algorithm_t) \
)

#if PSA_SINGLE_KEY_COUNT
/**
* @brief Required CBOR buffer size to encode a basic PSA key slot containing
* a single key.
*/
#define CBOR_BUF_SIZE_SINGLE_KEY ( CBOR_BUF_SIZE_START + \
3 + /* Bytestring encoding and size */ \
PSA_MAX_KEY_DATA_SIZE \
)
#endif /* PSA_SINGLE_KEY_COUNT */

#if PSA_ASYMMETRIC_KEYPAIR_COUNT
/**
* @brief Required CBOR buffer size to encode a basic PSA key slot containing
* an asymmetric key pair.
*/
#define CBOR_BUF_SIZE_KEY_PAIR ( CBOR_BUF_SIZE_START + \
1 + \
3 + PSA_BITS_TO_BYTES(PSA_MAX_PRIV_KEY_SIZE) + \
3 + PSA_EXPORT_PUBLIC_KEY_MAX_SIZE \
)
#endif /* PSA_ASYMMETRIC_KEYPAIR_COUNT */

#if PSA_PROTECTED_KEY_COUNT && IS_USED(MODULE_PSA_ASYMMETRIC)
/**
* @brief Required CBOR buffer size to encode a basic PSA key slot containing
* a key in protected memory.
*/
#define CBOR_BUF_SIZE_PROT_KEY ( CBOR_BUF_SIZE_START + \
1 + \
1 + sizeof(psa_key_slot_number_t) + \
3 + PSA_EXPORT_PUBLIC_KEY_MAX_SIZE \
)
#elif PSA_PROTECTED_KEY_COUNT
/**
* @brief Required CBOR buffer size to encode a basic PSA key slot containing
* a key in protected memory.
*/
#define CBOR_BUF_SIZE_PROT_KEY ( CBOR_BUF_SIZE_START + \
1 + \
1 + sizeof(psa_key_slot_number_t) \
)
#endif /* PSA_PROTECTED_KEY_COUNT */

/**
* @brief Encodes a basic key slot in CBOR
*
* Single Key Format:
* - [
* [ID, Type, Bits, Lifetime, [Usage, Algorithm]],
* h'key
* ]
*
* Asymmetric Key Pair Format:
* - [
* [ID, Type, Bits, Lifetime, [Usage, Algorithm]],
* [h'private_key, h'public_key]
* ]
*
* Protected Key Format:
* - [
* [ID, Type, Bits, Lifetime, [Usage, Algorithm]],
* [Slot No, *optional: h'public_key*]
* ]
*
* @param[in] slot Pointer to slot containing the key to encode
* @param[in] output Buffer to write the encoded key to
* @param[in] output_len Length of output buffer
* @param[out] output_size Pointer to write actual length of encoding
*
* @return psa_status_t
*/
psa_status_t psa_encode_key_slot(psa_key_slot_t *slot, uint8_t *output,
size_t output_len, size_t *output_size);

/**
* @brief Decode CBOR encoded key data and write to PSA key slot. Only decodes the key and should
* be called in combination with psa_decode_key_attributes.
*
* @param slot Pointer to key slot to write decoded key to
* @param cbor_buf Buffer containing CBOR encoded data
* @param cbor_buf_size Size of @p cbor_buf
* @return psa_status_t
*/
psa_status_t psa_decode_key_slot_data(psa_key_slot_t *slot, uint8_t *cbor_buf,
size_t cbor_buf_size);

/**
* @brief Decode CBOR PSA key attributes. Only decodes key attributes and not the actual key.
* Key can be decoded with psa_decode_key_slot_data.
*
* @param attr Key attribute struct to store decoded attributes
* @param cbor_buf Buffer containing CBOR encoded data
* @param cbor_buf_size Size of @p cbor_buf
* @return psa_status_t
*/
psa_status_t psa_decode_key_attributes(psa_key_attributes_t *attr, uint8_t *cbor_buf,
size_t cbor_buf_size);

#ifdef __cplusplus
}
#endif

#endif /* PSA_CRYPTO_CBOR_ENCODER_H */
/** @} */
73 changes: 73 additions & 0 deletions sys/psa_crypto/include/psa_crypto_persistent_storage.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/*
* Copyright (C) 2023 HAW Hamburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/

/**
* @ingroup sys_psa_crypto
* @defgroup sys_psa_crypto_pers_stor PSA Crypto Persistent Storage API
* @{
*
* @file psa_crypto_persistent_storage.h
* @brief
*
* @author Lena Boeckmann <[email protected]>
*
*/

#ifndef PSA_CRYPTO_PERSISTENT_STORAGE_H
#define PSA_CRYPTO_PERSISTENT_STORAGE_H

#ifdef __cplusplus
extern "C" {
#endif

#include "psa/crypto.h"

/**
* @brief Writes a CBOR encoded key slot to a file
*
* @param id ID of slot, used as filename
* @param input Pointer to CBOR encoded data
* @param input_len Length of CBOR encoded data
* @return psa_status_t
*/
psa_status_t psa_write_encoded_key_slot_to_file(psa_key_id_t id,
uint8_t* input,
size_t input_len);

/**
* @brief Reads a CBOR encoded key slot from a file
*
* @param id ID of the desired key
* @param output Output buffer to write CBOR data to
* @param output_size Size of output buffer
* @param output_data_len Actual length of CBOR encoded data
* @return psa_status_t
*/
psa_status_t psa_read_encoded_key_slot_from_file(psa_key_id_t id,
uint8_t *output,
size_t output_size,
size_t *output_data_len);

/**
* @brief Destroy a key in persistent storage
mguetschow marked this conversation as resolved.
Show resolved Hide resolved
*
* @note This will only remove the link to the key file without erasing the
* key from the flash. The key material can still be recovered by someone
* with access to the hardware.
*
* @param key_id ID of the key to be destroyed
* @return psa_status_t
*/
psa_status_t psa_destroy_persistent_key(psa_key_id_t key_id);

#ifdef __cplusplus
}
#endif

#endif /* PSA_CRYPTO_PERSISTENT_STORAGE_H */
/** @} */
53 changes: 53 additions & 0 deletions sys/psa_crypto/include/psa_crypto_slot_management.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,51 @@ typedef struct {
#endif /* PSA_SINGLE_KEY_COUNT */
} psa_key_slot_t;

#if PSA_PROTECTED_KEY_COUNT
/**
* @brief Structure for a protected key slot.
*
* These slots hold Slot Numbers for keys in protected storage and, if the key type is an
* asymmetric key pair, the public key.
*/
typedef struct {
clist_node_t node;
size_t lock_count;
psa_key_attributes_t attr;
struct prot_key_data {
psa_key_slot_number_t slot_number;
#if IS_USED(MODULE_PSA_ASYMMETRIC)
uint8_t pubkey_data[PSA_EXPORT_PUBLIC_KEY_MAX_SIZE];
size_t pubkey_data_len;
#endif
} key;
} psa_prot_key_slot_t;
#endif /* PSA_PROTECTED_KEY_COUNT */

#if PSA_ASYMMETRIC_KEYPAIR_COUNT
/**
* @brief Structure for asymmetric key pairs.
*
* Contains asymmetric private and public key pairs.
*
*/
typedef struct {
clist_node_t node;
size_t lock_count;
psa_key_attributes_t attr;
struct key_pair_data {
/** Contains asymmetric private key*/
uint8_t privkey_data[PSA_BITS_TO_BYTES(PSA_MAX_PRIV_KEY_SIZE)];
/** Contains actual size of asymmetric private key */
size_t privkey_data_len;
/** Contains asymmetric public key */
uint8_t pubkey_data[PSA_EXPORT_PUBLIC_KEY_MAX_SIZE];
/*!< Contains actual size of asymmetric private key */
size_t pubkey_data_len;
} key;
} psa_key_pair_slot_t;
#endif /* PSA_ASYMMETRIC_KEYPAIR_COUNT */

/**
* @brief Initializes the allocated key slots and prepares the internal key slot lists.
*/
Expand Down Expand Up @@ -165,6 +210,14 @@ void psa_wipe_all_key_slots(void);
*/
psa_status_t psa_get_and_lock_key_slot(psa_key_id_t id, psa_key_slot_t **slot);

/**
* @brief Store a key slot in persistent storage
*
* @param slot Pointer to slot to store in persistent storage
* @return psa_status_t
*/
psa_status_t psa_persist_key_slot_in_storage(psa_key_slot_t *slot);

/**
* @brief Find a currently empty key slot that is appropriate for the key.
*
Expand Down
Loading
Loading