Skip to content

Commit

Permalink
sys/psa_crypto: implement persistent key storage
Browse files Browse the repository at this point in the history
  • Loading branch information
Einhornhool committed Apr 10, 2024
1 parent a9e7b44 commit 07faa14
Show file tree
Hide file tree
Showing 26 changed files with 2,219 additions and 87 deletions.
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 @@ -1503,6 +1503,10 @@ psa_status_t psa_copy_key(psa_key_id_t source_key,
* 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
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`
*
* @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 <lena.boeckmann@haw-hamburg.de>
*
*/

#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 <lena.boeckmann@haw-hamburg.de>
*
*/

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

0 comments on commit 07faa14

Please sign in to comment.