mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
00e25adfe3
sys/psa_crypto: one-shot Chacha20 support
1069 lines
46 KiB
Plaintext
1069 lines
46 KiB
Plaintext
/**
|
||
* @defgroup sys_psa_crypto PSA Cryptographic API
|
||
* @ingroup sys
|
||
* @brief Implements the PSA Crypto API specification.
|
||
* @see https://armmbed.github.io/mbed-crypto/html/
|
||
*
|
||
* @warning This implementation is not complete and not yet thoroughly tested.
|
||
* Please do not use this module in production, as it may introduce security issues.
|
||
*
|
||
* @note This implementation is not complete and will be successively expanded.
|
||
*
|
||
* About {#About}
|
||
* =====
|
||
* This module implements the PSA Cryptography API Version 1.1 as specified
|
||
* [here](https://armmbed.github.io/mbed-crypto/html/) and the PSA Status code API Version 1.0
|
||
* as specified [here](https://arm-software.github.io/psa-api/status-code/1.0/).
|
||
* It provides an OS level access to cryptographic operations and supports software and hardware
|
||
* backends as well as the use of secure elements.
|
||
* The API automatically builds a hardware backend for an operation, if there's one available,
|
||
* otherwise it falls back to software. Specific backends can be configured, if needed.
|
||
* For configuration options see [Configuration](#configuration).
|
||
*
|
||
* PSA Crypto has an integrated key management module, which stores keys internally
|
||
* without exposing them to applications. To learn how to use keys with PSA,
|
||
* read [Using Keys](#using-keys).
|
||
*
|
||
* A basic usage and configuration example can be found in `examples/psa_crypto`.
|
||
* For more usage instructions, please read the documentation.
|
||
*
|
||
* If you want to add your own crypto backend, see [Porting Guide](#porting-guide).
|
||
*
|
||
* Basic Usage
|
||
* ===
|
||
* To use PSA Crypto, add `psa/crypto.h` to your includes. This will make all
|
||
* operations and macros available.
|
||
*
|
||
* Call `psa_crypto_init()` before calling any other operation.
|
||
*
|
||
* ## Structure Initialization
|
||
* Whenever you declare a PSA Crypto structure (e.g. operation contexts or key attributes),
|
||
* it needs to be initialized with zeroes. A structure that is not initialized will be interpreted
|
||
* by PSA as *active* and can not be used for a new operation.
|
||
* The example function and macro shown below result in the same thing: A new, inactive structure.
|
||
*
|
||
* @code {.c}
|
||
* // Choose one of these options
|
||
* psa_hash_operation_t hash_op = psa_hash_operation_init();
|
||
* psa_hash_operation_t hash_op = PSA_HASH_OPERATION_INIT;
|
||
* @endcode
|
||
*
|
||
* An already active operation can be set to zero by reinitializing it. It then becomes *inactive*
|
||
* again and can be used for a new operation.
|
||
*
|
||
* When errors occur during execution, PSA resets the operation contexts and makes them
|
||
* *inactive*, to prevent unauthorized access to an operation's state.
|
||
* Users can also call `psa_<operation>_abort()` anytime in between function calls to do the same.
|
||
*
|
||
* Using Keys {#using-keys}
|
||
* ===
|
||
* PSA can only operate on keys, that are registered with and stored within the internal
|
||
* key storage module. This means you need to either generate keys with PSA or
|
||
* import an existing key.
|
||
* For this purpose there are a number of
|
||
* [key management functions](https://armmbed.github.io/mbed-crypto/html/api/keys/management.html)
|
||
* (external link).
|
||
*
|
||
* ## Key Attributes
|
||
* When creating a key for PSA, the implementation needs to know what kind of key it is
|
||
* dealing with, what it can be used for, where it's supposed to be stored, etc.
|
||
* That information needs to be specified in a set of
|
||
* [Key Attributes](https://armmbed.github.io/mbed-crypto/html/api/keys/attributes.html)
|
||
* (external link).
|
||
*
|
||
* The example below defines attributes for an AES-128 key, which can be used for CBC encryption
|
||
* and decryption and will be stored in local volatile memory.
|
||
* @code
|
||
* // Initializes empty attributes structure
|
||
* psa_key_attributes_t attributes = psa_key_attributes_init();
|
||
*
|
||
* // Set all necessary attributes
|
||
* psa_set_key_lifetime(&attributes, PSA_KEY_LIFETIME_VOLATILE);
|
||
* psa_set_key_type(&attributes, PSA_KEY_TYPE_AES);
|
||
* psa_set_key_bits(&attributes, 128);
|
||
* psa_set_key_algorithm(&attributes, PSA_ALG_CBC_NO_PADDING);
|
||
* psa_set_key_usage_flags(&attributes, (PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT));
|
||
* @endcode
|
||
*
|
||
* After setting the attributes, an exiting key can be imported:
|
||
* @code
|
||
* uint8_t aes_key[] = { ... };
|
||
* psa_key_id_t key_id = 0; // Will be set by PSA Crypto
|
||
* psa_status_t status = psa_import_key(&attributes, aes_key, sizeof(aes_key), &key_id);
|
||
* @endcode
|
||
* The PSA Crypto implementation will assign an identifier to the key and return it
|
||
* via the `key_id` parameter. This identifier can then be used for operations with this
|
||
* specific key.
|
||
* @code
|
||
* uint8_t PLAINTEXT[] = { ... };
|
||
* // Buffer sizes can be calculated with macros
|
||
* size_t output_buf_size = PSA_CIPHER_ENCRYPT_OUTPUT_SIZE(PSA_KEY_TYPE_AES, PSA_ALG_CBC_NO_PADDING,sizeof(PLAINTEXT));
|
||
* uint8_t output_buffer[output_buf_size];
|
||
*
|
||
* status = psa_cipher_encrypt(key_id, PSA_ALG_CBC_NO_PADDING, PLAINTEXT, sizeof(PLAINTEXT),output_buffer, sizeof(output_buffer), &output_length));
|
||
* @endcode
|
||
*
|
||
* All the supported key types, algorithms and usage flags can be found in the documentation.
|
||
*
|
||
* ### Key Lifetime {#key-lifetime}
|
||
* #### Volatile vs. Persistent
|
||
* The PSA API specifies two ways of storing keys: volatile and persistent. Volatile
|
||
* keys will be stored only in RAM, which means they will be destroyed after application
|
||
* termination or a device reset.
|
||
* 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 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
|
||
* of two values: persistence and location. The location defines the actual memory location
|
||
* of the key (e.g. whether the key will be stored in RAM, in a hardware protected memory slot
|
||
* or on an external device like a secure element).
|
||
*
|
||
* The persistence value defines whether the key will be stored in RAM (volatile)
|
||
* in flash (persistent).
|
||
* Some default values that exist are:
|
||
* - @ref PSA_KEY_LIFETIME_VOLATILE (stored in local, volatile memory)
|
||
* - @ref PSA_KEY_LIFETIME_PERSISTENT (stored in local, persistent memory)
|
||
*
|
||
* Other lifetime values can be constructed with the macro
|
||
* `PSA_KEY_LIFETIME_FROM_PERSISTENCE_AND_LOCATION(persistence, location)`.
|
||
* All supported `PSA_KEY_PERSISTENCE_*` and `PSA_KEY_LOCATION_*` values can be combined.
|
||
*
|
||
* In addition to the location values defined by the specification, this implementation also
|
||
* supports values for [Secure Elements](#secure-elements).
|
||
*
|
||
* Configuration {#configuration}
|
||
* ===
|
||
* Currently there are two ways to configure PSA Crypto: Kconfig and Makefiles. An example for both
|
||
* can be found in `RIOT/examples/psa_crypto`.
|
||
*
|
||
* ## Kconfig
|
||
* We recommend using Kconfig and choosing your features in `menuconfig`.
|
||
* You can access the GUI by calling
|
||
*
|
||
* @code
|
||
* TEST_KCONFIG=1 BOARD=<your board> make menuconfig
|
||
* @endcode
|
||
*
|
||
* from your application directory.
|
||
* There you can find the available PSA features and options under `System->PSA Crypto`.
|
||
* If you only select the operations you want to use (e.g. `PSA Ciphers->AES-128 CBC`), Kconfig
|
||
* will automatically select the best backend for you depending on the board (e.g. a hardware
|
||
* accelerator if it is available). Optionally you can force a custom backend.
|
||
*
|
||
* Further you can specify the exact number of keys you need to store (section `PSA Key Management
|
||
* Configuration` in `menuconfig`), or choose your [Secure Element](#secure-elements)
|
||
* configurations.
|
||
*
|
||
* Alternatively you can create an `app.config.test` file in your application folder
|
||
* and choose your symbols there (see `examples/psa_crypto`).
|
||
*
|
||
* In the `app.config.test` file, modules can be chosen with the following syntax:
|
||
* `CONFIG_MODULE_<MODULENAME>=y`, as shown below.
|
||
* @code
|
||
* CONFIG_MODULE_PSA_CRYPTO=y
|
||
* CONFIG_MODULE_PSA_CIPHER=y
|
||
* CONFIG_MODULE_PSA_CIPHER_AES_128_CBC=y
|
||
* @endcode
|
||
*
|
||
* ## Makefiles
|
||
* If you don't want to use Kconfig, you can use the traditional way in RIOT of selecting
|
||
* modules in your application Makefile.
|
||
*
|
||
* Here you need to set the base module and individual modules for each operation you need.
|
||
* The example below also chooses a default backend depending on your board.
|
||
* @code
|
||
* // Base module: this is required!
|
||
* USEMODULE += psa_crypto
|
||
*
|
||
* USEMODULE += psa_cipher
|
||
* USEMODULE += psa_cipher_aes_128_cbc
|
||
* @endcode
|
||
*
|
||
* If desired, you can choose a specific backend at compile time. For this you need to specify
|
||
* that you want to set a custom backend and then explicitly choose the one you want (see below).
|
||
* @code
|
||
* USEMODULE += psa_cipher_aes_128_cbc_custom_backend
|
||
* USEMODULE += psa_cipher_aes_128_cbc_backend_riot
|
||
* @endcode
|
||
*
|
||
* The currently available modules, are listed [below](#available-modules).
|
||
*
|
||
* ## Key Slot Types {#configuration-keys}
|
||
* The key management of PSA keeps track of keys by storing them in virtual key slot
|
||
* representations, along with their attributes. Since keys can come in various sizes,
|
||
* it would be inefficient to allocate the same amount of memory for all keys.
|
||
* To reduce the amount of memory used for key storage, PSA internally differentiates between
|
||
* three types of key slots (see below). Depending on the operations your application uses, PSA will
|
||
* automatically detect the key sizes needed and will allocate the required memory.
|
||
* The number of key slots allocated of each type is set to five per default, but can be changed by
|
||
* the user depending on their requirements.
|
||
*
|
||
* | Single Key Slot | Asymmetric Key Slot | Protected Key Slot |
|
||
* |----------------|---------------------|--------------------|
|
||
* | Single keys or unstructured data,<br>e.g. AES keys or asymmetric<br>public keys in local memory | Asymmetric key pairs<br>(private and public parts) <br>in local memory | Any keys stored on a secure<br>element or on-chip in<br>hardware protected memory |
|
||
*
|
||
* If you want to change the default number of allocated key slots you can do so by
|
||
* updating the number in `menuconfig`, or adding them to the `app.config.test` file like so:
|
||
* @code
|
||
* CONFIG_PSA_SINGLE_KEY_COUNT=3
|
||
* CONFIG_PSA_ASYMMETRIC_KEYPAIR_COUNT=1
|
||
* CONFIG_PSA_PROTECTED_KEY_COUNT=2
|
||
* @endcode
|
||
*
|
||
* When using Makefiles, you can pass CFLAGS as shown below.
|
||
* @code
|
||
* CFLAGS += -DCONFIG_PSA_SINGLE_KEY_COUNT=3
|
||
* CFLAGS += -DCONFIG_PSA_ASYMMETRIC_KEYPAIR_COUNT=1
|
||
* 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.
|
||
* If you want to specify a backend other than the default, you need to select
|
||
* `psa_<operation>_custom_backend` in addition to the actual backend module.
|
||
*
|
||
* The names listed are are the version used in makefiles with the
|
||
* `USEMODULE += <modulename>` syntax.
|
||
* In Kconfig you don't need to know the exact names, you can simply choose the features in
|
||
* `menuconfig`.
|
||
* 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
|
||
*
|
||
* #### NIST ECC P192
|
||
* - psa_asymmetric_ecc_p192r1
|
||
* - psa_asymmetric_ecc_p192r1_backend_periph
|
||
* - psa_asymmetric_ecc_p192r1_custom_backend
|
||
* - psa_asymmetric_ecc_p192r1_backend_microecc
|
||
*
|
||
* #### NIST ECC P192
|
||
* - psa_asymmetric_ecc_p256r1
|
||
* - psa_asymmetric_ecc_p256r1_backend_periph
|
||
* - psa_asymmetric_ecc_p256r1_custom_backend
|
||
* - psa_asymmetric_ecc_p256r1_backend_microecc
|
||
*
|
||
* #### Ed25519
|
||
* - psa_asymmetric_ecc_ed25519
|
||
* - psa_asymmetric_ecc_ed25519_backend_periph
|
||
* - psa_asymmetric_ecc_ed25519_custom_backend
|
||
* - psa_asymmetric_ecc_ed25519_backend_c25519
|
||
*
|
||
* ### Ciphers
|
||
* - Base: psa_cipher
|
||
*
|
||
* #### AES ECB
|
||
* - psa_cipher_aes_128_ecb
|
||
* - psa_cipher_aes_128_ecb_backend_riot
|
||
*
|
||
* #### AES CBC
|
||
* - psa_cipher_aes_128_cbc
|
||
* - psa_cipher_aes_128_cbc_backend_periph
|
||
* - psa_cipher_aes_128_cbc_custom_backend
|
||
* - psa_cipher_aes_128_cbc_backend_riot
|
||
* - psa_cipher_aes_192_cbc
|
||
* - psa_cipher_aes_192_cbc_custom_backend
|
||
* - psa_cipher_aes_192_cbc_backend_riot
|
||
* - psa_cipher_aes_256_cbc
|
||
* - psa_cipher_aes_256_cbc_custom_backend
|
||
* - psa_cipher_aes_256_cbc_backend_riot
|
||
*
|
||
* #### CHACHA20
|
||
* - psa_cipher_chacha20
|
||
* - psa_cipher_chacha20_backend_periph
|
||
* - psa_cipher_chacha20_custom_backend
|
||
* - psa_cipher_chacha20_backend_riot
|
||
*
|
||
* ### Hashes
|
||
* - Base: psa_hash
|
||
*
|
||
* #### MD5
|
||
* - psa_hash_md5
|
||
* - psa_hash_md5_custom_backend
|
||
* - psa_hash_md5_backend_riot
|
||
*
|
||
* #### SHA 1
|
||
* - psa_hash_sha_1
|
||
* - psa_hash_sha_1_backend_periph
|
||
* - psa_hash_sha_1_custom_backend
|
||
* - psa_hash_sha_1_backend_riot
|
||
*
|
||
* #### SHA 224
|
||
* - psa_hash_sha_224
|
||
* - psa_hash_sha_224_backend_periph
|
||
* - psa_hash_sha_224_custom_backend
|
||
* - psa_hash_sha_224_backend_riot
|
||
*
|
||
* #### SHA 256
|
||
* - psa_hash_sha_256
|
||
* - psa_hash_sha_256_backend_periph
|
||
* - psa_hash_sha_256_custom_backend
|
||
* - psa_hash_sha_256_backend_riot
|
||
*
|
||
* #### SHA 384
|
||
* - psa_hash_sha_384
|
||
* - psa_hash_sha_384_backend_periph
|
||
* - psa_hash_sha_384_custom_backend
|
||
* - psa_hash_sha_384_backend_riot
|
||
*
|
||
* #### SHA 512
|
||
* - psa_hash_sha_512
|
||
* - psa_hash_sha_512_backend_periph
|
||
* - psa_hash_sha_512_custom_backend
|
||
* - psa_hash_sha_512_backend_riot
|
||
*
|
||
* #### SHA 512/224
|
||
* - psa_hash_sha_512_224
|
||
* - psa_hash_sha_512_224_backend_periph
|
||
* - psa_hash_sha_512_224_custom_backend
|
||
* - psa_hash_sha_512_224_backend_riot
|
||
*
|
||
* #### SHA 512/256
|
||
* - psa_hash_sha_512_256
|
||
* - psa_hash_sha_512_256_backend_periph
|
||
* - psa_hash_sha_512_256_custom_backend
|
||
* - psa_hash_sha_512_256_backend_riot
|
||
*
|
||
* #### SHA 3/256
|
||
* - psa_hash_sha3_256
|
||
* - psa_hash_sha3_256_backend_periph
|
||
* - psa_hash_sha3_256_custom_backend
|
||
* - psa_hash_sha3_256_backend_riot
|
||
*
|
||
* #### SHA 3/384
|
||
* - psa_hash_sha3_384
|
||
* - psa_hash_sha3_384_backend_periph
|
||
* - psa_hash_sha3_384_custom_backend
|
||
* - psa_hash_sha3_384_backend_riot
|
||
*
|
||
* #### SHA 3/512
|
||
* - psa_hash_sha3_512
|
||
* - psa_hash_sha3_512_backend_periph
|
||
* - psa_hash_sha3_512_custom_backend
|
||
* - psa_hash_sha3_512_backend_riot
|
||
*
|
||
* ### MAC
|
||
* - Base: psa_mac
|
||
*
|
||
* #### HMAC SHA 256
|
||
* - psa_mac_hmac_sha_256
|
||
* - psa_mac_hmac_sha_256_backend_periph
|
||
* - psa_mac_hmac_sha_256_custom_backend
|
||
* - psa_mac_hmac_sha_256_backend_riot
|
||
*
|
||
* ### Secure Elements
|
||
* Base:
|
||
* - psa_secure_element
|
||
* - psa_secure_element_multiple
|
||
*
|
||
* #### SE Types
|
||
* - psa_secure_element_ateccx08a
|
||
* - psa_secure_element_ateccx08a_cipher_aes_128
|
||
* - psa_secure_element_ateccx08a_ecc_p256
|
||
* - psa_secure_element_ateccx08a_hmac_sha256
|
||
*
|
||
* Random Number Generation {#rng}
|
||
* ===
|
||
* Currently uses the [RIOT Random Module](#sys_random) as a backend.
|
||
* See the documentation for configuration options.
|
||
*
|
||
* Secure Elements {#secure-elements}
|
||
* ===
|
||
*
|
||
* An example showing the use of SEs can be found in `examples/psa_crypto`.
|
||
*
|
||
* To use secure elements, you first need to assign a static location value to each device,
|
||
* so PSA can find it. If you only use one device, you can use
|
||
* `PSA_KEY_LOCATION_PRIMARY_SECURE_ELEMENT`. For additional devices this value must be within
|
||
* the range of `PSA_KEY_LOCATION_SE_MIN` and `PSA_KEY_LOCATION_SE_MAX`.
|
||
* When booting the system, the `auto_init` module in RIOT will automatically register the device
|
||
* with the location with PSA Crypto.
|
||
*
|
||
* You can now import or create keys on the secure element by constructing a key lifetime containing
|
||
* a device's location value.
|
||
*
|
||
* @code {.c}
|
||
* psa_key_lifetime_t lifetime =
|
||
* PSA_KEY_LIFETIME_FROM_PERSISTENCE_AND_LOCATION (PSA_KEY_LIFETIME_VOLATILE,
|
||
PSA_KEY_LOCATION_PRIMARY_SECURE_ELEMENT);
|
||
* @endcode
|
||
*
|
||
* Some secure elements come with their own key management and device configurations. In this case
|
||
* the configuration parameters must be passed to PSA Crypto during the registration. For this, you
|
||
* need to define a `psa_se_config_t` structure containing the configuration.
|
||
* PSA Crypto will use this structure to keep track of what types of keys are allowed on the device
|
||
* and how much storage is available.
|
||
* Where this structure should be placed, how it looks and what parameters are required depends
|
||
* on the type of your device.
|
||
*
|
||
* A good place to define that structure and the location values is a drivers `<driver>_params.h`
|
||
* file, but this may vary depending on how your device is integrated in RIOT.
|
||
*
|
||
* For detailed, device specific information, please check the device driver documentation or
|
||
* the example.
|
||
*
|
||
* ## Available Devices and Drivers
|
||
* - ATECCX08A: [Microchip Cryptoauthlib as a PSA backend](#psa-cryptoauthlib)
|
||
*
|
||
* ## Main SE Configuration
|
||
* To use SEs, the appropriate modules must be chosen in Kconfig:
|
||
* @code
|
||
* CONFIG_PSA_SECURE_ELEMENT=y
|
||
* CONFIG_PSA_SECURE_ELEMENT_ATECCX08A=y // device example
|
||
* CONFIG_PSA_SECURE_ELEMENT_ATECCX08A_ECC_P256=y
|
||
* @endcode
|
||
*
|
||
* or added to the the Makefile:
|
||
* @code
|
||
* USEMODULE += psa_secure_element
|
||
* USEMODULE += psa_secure_element_ateccx08a // device example
|
||
* USEMODULE += psa_secure_element_ateccx08a_ecc_p256
|
||
* @endcode
|
||
*
|
||
* This implementation supports the use of one or more secure elements (SE) as backends. In this
|
||
* case the number of used secure elements must be specified (must be at least 2 and at most 255).
|
||
* When using more than one SE, add
|
||
* @code
|
||
* CONFIG_PSA_SECURE_ELEMENT_MULTIPLE=y
|
||
* CONFIG_PSA_MAX_SE_COUNT=2 // or any other number between 2 and 255
|
||
* @endcode
|
||
*
|
||
* or, respectively,
|
||
*
|
||
* @code
|
||
* USEMODULE += psa_secure_element_multiple
|
||
* CFLAGS += -DCONFIG_PSA_MAX_SE_COUNT=2 // or any other number between 2 and 255
|
||
* @endcode
|
||
*
|
||
* Porting Guide {#porting-guide}
|
||
* ===
|
||
* This porting guide focuses on how to add your software library or hardware driver
|
||
* as a backend to PSA Crypto without actually touching the PSA implementation.
|
||
* We will provide some [general information](#porting-general) and then some case
|
||
* examples for different kinds of backends:
|
||
* - [Software Libraries](#porting-software)
|
||
* - [Hardware Drivers](#porting-hardware)
|
||
* - [Secure Elements](#porting-secure-elements)
|
||
*
|
||
* Some examples to look at are:
|
||
* - [RIOT hash module](#sys_hashes)
|
||
* - [RIOT cipher module](#sys_crypto)
|
||
* - [Micro-ECC](#pkg_micro_ecc)
|
||
* - [CryptoCell 310 driver](#pkg_driver_cryptocell_310).
|
||
*
|
||
* An example integrating a secure element can be found in the
|
||
* [Cryptoauthlib Package](#pkg_cryptoauthlib).
|
||
*
|
||
* ## General Information {#porting-general}
|
||
* ### Error Values
|
||
* You should always check the status of your function calls and translate your library's or
|
||
* driver's errors to PSA error values (please be as thorough as possible).
|
||
* The PSA Crypto specification describes exactly what kind of error values should be returned
|
||
* by which function. Please read the API documentation and comply with the instructions.
|
||
* We recommend writing a`<mylibrary>_to_psa_error()` function right in the beginning (see for
|
||
* example `CRYS_to_psa_error()` in
|
||
* `pkg/driver_cryptocell_310/psa_cryptocell_310/error_conversion.c`).
|
||
*
|
||
* ### The Build System
|
||
* As mentioned before, there are two ways of selecting build time configurations in RIOT: Kconfig
|
||
* and Makefiles.
|
||
* Kconfig dependency resolution is currently an experimental feature and will at some point
|
||
* replace Makefiles. Until then, our implementation needs to support both, which means we need
|
||
* to define features and symbols in multiple places.
|
||
* Luckily, the modules have the exact same names in both systems, which makes the transfer easier.
|
||
* The examples below show both ways.
|
||
*
|
||
* ### Modules {#module-names}
|
||
* In RIOT, module names are generated from path names, so if you create a directory for
|
||
* your sourcefiles, the module name will be the same as the directory name. It is possible
|
||
* to change that by declaring a new module name in the Makefile by adding the line
|
||
* `MODULE := your_module_name`.
|
||
*
|
||
* If you leave it like this, all sourcefiles in the path corresponding to the module name will be
|
||
* built (e.g. if you choose the module `hashes`, all files in `sys/hashes` will be included).
|
||
* For better configurability it is possible to add submodules (see
|
||
* `sys/hashes/psa_riot_hashes` for example).
|
||
* In that case the base module name will be the directory name and each file inside the directory
|
||
* becomes its own submodule that must be explicitly chosen. The module name will then be the
|
||
* directory name with the file name as a postfix.
|
||
* For example:
|
||
* @code
|
||
* USEMODULE += hashes
|
||
* USEMODULE += psa_riot_hashes
|
||
* USEMODULE += psa_riot_hashes_sha_256
|
||
*
|
||
* will build the file at `sys/hashes/psa_riot_hashes/sha_256.c`, but none of the other files in
|
||
* the directory.
|
||
*
|
||
* To enable submodules for your implementation add the following to the directory makefile:
|
||
* @code
|
||
* BASE_MODULE := psa_<modulename>
|
||
* SUBMODULES := 1
|
||
* @endcode
|
||
*
|
||
* We also need to create so-called pseudomodules for each available submodule.
|
||
* Those must follow the scheme `psa_<modulename>_<filename>`.
|
||
* Where they are declared depends on where your module is located. Pseudomodules in `RIOT/sys` must
|
||
* be added in `pseudomodules.inc.mk`.
|
||
* When integrating packages or drivers, the pseudomodules can be added in the `Makefile.include`
|
||
* file of the individual module's directory (see `pkg/micro-ecc/Makefile.include`).
|
||
*
|
||
* When adding backends to PSA Crypto, please name your modules in ways that fit within the
|
||
* current naming scheme: `psa_<library>_<algorithm>`. Also, when adding software libraries and
|
||
* hardware drivers, use the submodule approach. That makes PSA Crypto more configurable.
|
||
*
|
||
* The drawback of the submodule approach is, that if one of our sourcefiles depends on
|
||
* another sourcefile in the same folder, we need to select it explicitly. For example, in
|
||
* `pkg/driver_cryptocell_310/psa_cryptocell_310` you can see that there are some common source
|
||
* files that all the others use (e.g. for hashes there is a `hashes_common.c` file).
|
||
*
|
||
* If that is the case for your driver, you need to make sure the modules are selected in
|
||
* the Kconfig file as well as the `Makefile.dep` file (see `psa_cryptocell_310/Makefile.dep` or
|
||
* `psa_cryptocell_310/Kconfig`).
|
||
*
|
||
* ### Adding Glue Code {#glue-code}
|
||
* We define a number of wrapper APIs, which are called by PSA to invoke crypto backends.
|
||
* Software libraries and hardware drivers use the same methods, secure elements are handled
|
||
* in a different way (see [Case Example – Secure Elements](#porting-secure-elements) for details).
|
||
*
|
||
* The names, parameters and return values for wrapper methods are defined in header files in
|
||
* `sys/psa_crypto/include/psa_<algorithm>.h`.
|
||
* The functions declared in those files are the ones that are currently supported by this
|
||
* PSA implementation. They will be extended in the future.
|
||
*
|
||
* You need to implement those functions with glue code calling your library or driver code
|
||
* and converting types and error values between PSA and your backend.
|
||
* Below is an example of how this might look (it's very reduced, your library may need
|
||
* much more glue code).
|
||
* @code {.c}
|
||
* psa_status_t psa_ecc_p256r1_sign_hash(const psa_key_attributes_t *attributes,
|
||
* psa_algorithm_t alg, const uint8_t *key_buffer,
|
||
* size_t key_buffer_size, const uint8_t *hash,
|
||
* size_t hash_length, uint8_t *signature,
|
||
* size_t signature_size, size_t *signature_length)
|
||
* {
|
||
* int status = <libraryname>_<sign_hash_func>(key_buffer, hash, hash_length,
|
||
* signature, signature_length, curve);
|
||
*
|
||
* if (status != SUCCESS) {
|
||
* return <libraryname>_status_to_psa_error(status);
|
||
* }
|
||
*
|
||
* (void)alg;
|
||
* (void)attributes;
|
||
* (void)key_buffer_size;
|
||
* return PSA_SUCCESS;
|
||
* }
|
||
* @endcode
|
||
*
|
||
* ### Operation Contexts
|
||
* Some cryptographic operations use driver specific context to store the operation state in
|
||
* between function calls. These must be defined somewhere. Examples can be found in
|
||
* `pkg/driver_cryptocell_310/include/psa_periph_hashes_ctx.h` and
|
||
* `sys/include/hashes/psa/riot_hashes.h`.
|
||
*
|
||
* When defining the contexts for a hardware driver, all you need to do is add a file called
|
||
* `psa_periph_<algorithm>_ctx.h` to your driver's include folder and define the available types
|
||
* (see supported [types](#supported-types) below).
|
||
* Those files are automatically included in `crypto_includes.h` and it is important that they
|
||
* always have the same name for each algorithm.
|
||
*
|
||
* When defining the contexts for a software library, the headerfile should be called
|
||
* `<library>_<algorithm>.h` (e.g. `riot_hashes.h`) and must be added to `crypto_includes.h` as
|
||
* shown below:
|
||
* @code
|
||
* #if IS_USED(MODULE_PSA_<LIBRARY>_<ALGORITHM>)
|
||
* #include "<library>/<library>_<algorithm>.h"
|
||
* #endif
|
||
* @endcode
|
||
*
|
||
* When defining the context types, those must always depend on the specific algorithm module,
|
||
* for example
|
||
* @code
|
||
* #if IS_USED(MODULE_PSA_<LIBRARY>_HASHES_SHA_256)
|
||
* #include "path/to/headerfile_containing_the_driver_context_definition"
|
||
*
|
||
* typedef <library_context_type_t> psa_hashes_sha256_ctx_t;
|
||
* #endif
|
||
* @endcode
|
||
*
|
||
* #### Hashes {#supported-types}
|
||
* - `psa_hashes_md5_ctx_t`
|
||
* - `psa_hashes_sha1_ctx_t`
|
||
* - `psa_hashes_sha224_ctx_t`
|
||
* - `psa_hashes_sha256_ctx_t`
|
||
* - `psa_hashes_sha384_ctx_t`
|
||
* - `psa_hashes_sha512_ctx_t`
|
||
* - `psa_hashes_sha512_224_ctx_t`
|
||
* - `psa_hashes_sha512_256_ctx_t`
|
||
*
|
||
* #### Ciphers
|
||
* - `psa_cipher_aes_128_ctx_t`
|
||
* - `psa_cipher_aes_192_ctx_t`
|
||
* - `psa_cipher_aes_256_ctx_t`
|
||
*
|
||
* Secure Elements need their own contexts. For this,
|
||
* see [Case Example – Secure Elements](#porting-secure-elements).
|
||
*
|
||
* ## Adding a Backend
|
||
* The integration of hardware drivers, software libraries and secure element drivers
|
||
* differs a bit. Below we describe the necessary steps for each of them.
|
||
*
|
||
* ### Case Example – A Software Library {#porting-software}
|
||
* Software libraries are the easiest backends, because they are not platform or hardware
|
||
* specific. They can generally run on all platforms in RIOT and we can
|
||
* combine different software backends for different operations (we could, for example,
|
||
* use the Micro-ECC package for ECC NIST curves and the C25519 package for operations with
|
||
* the Curve25519).
|
||
*
|
||
* Let's say we have an imaginary software library called `FancyCrypt` and want to use
|
||
* it as a backend of PSA. We've already added it to RIOT as a third party package in
|
||
* `pkg/fancycrypt`.
|
||
* Our library provides hashes and elliptic curve operations and to make it accessible to
|
||
* PSA Crypto we need to write wrappers for our API calls.
|
||
*
|
||
* First we create a folder called `psa_fancycrypt` in the package directory. Inside we create
|
||
* a file with the name of each operation you want to integrate, e.g. `p256.c` and
|
||
* `hashes_sha_224.c` (when adding operations, remember that the path of the files will also
|
||
* be the [module name](#module-names), so please comply with the current naming scheme).
|
||
*
|
||
* In these files we need to implement the methods that are called by PSA as described
|
||
* [above](#glue-code).
|
||
*
|
||
* #### Adding Makefiles
|
||
* We add a Makefile to the `psa_fancycrypt` folder with the following content:
|
||
* @code {.c}
|
||
* BASE_MODULE := psa_fancycrypt
|
||
* SUBMODULES := 1
|
||
*
|
||
* include $(RIOTBASE)/Makefile.base
|
||
* @endcode
|
||
*
|
||
* This tells RIOT that the `psa_fancycrypt` module has submodules, which can be selected
|
||
* individually.
|
||
*
|
||
* In `pkg/fancycrypt` we now need to declare explicit pseudomodules in `Makefile.include` and add
|
||
* the `psa_fancycrypt` folder to the source files and the `sys/psa_crypto/include` folder to the
|
||
* includes.
|
||
* These should be dependent on the PSA Crypto module as shown below.
|
||
*
|
||
* @code
|
||
* ifneq (,$(filter psa_fancycrypt_%, $(USEMODULE)))
|
||
* PSEUDOMODULES += psa_fancycrypt_hashes_sha_256
|
||
* PSEUDOMODULES += psa_fancycrypt_p256
|
||
* DIRS += $(RIOTPKG)/fancycrypt/psa_fancycrypt
|
||
* INCLUDES += -I$(RIOTBASE)/sys/psa_crypto/include
|
||
* endif
|
||
* @endcode
|
||
*
|
||
* If the implementation has any dependencies, they need to be added in `Makefile.dep`, for example:
|
||
* @code
|
||
* USEMODULE += psa_fancycrypt
|
||
* USEMODULE += psa_fancycrypt_error_conversion
|
||
*
|
||
* ifneq (,$(filter psa_fancycrypt_hashes_sha1,$(USEMODULE)))
|
||
* USEMODULE += psa_fancycrypt_hashes_common
|
||
* endif
|
||
* @endcode
|
||
*
|
||
* #### Adding a Kconfig file
|
||
* We add a file called `Kconfig` to the `psa_fancycrypt` folder. Here we declare
|
||
* the modules for Kconfig like so:
|
||
* @code
|
||
* config MODULE_PSA_FANCYCRYPT_HASHES_SHA_256
|
||
* bool
|
||
* depends on MODULE_PSA_CRYPTO
|
||
* select MODULE_PSA_FANCYCRYPT
|
||
*
|
||
* config MODULE_PSA_FANCYCRYPT_P256
|
||
* bool
|
||
* depends on MODULE_PSA_CRYPTO
|
||
* select MODULE_PSA_FANCYCRYPT
|
||
*
|
||
* config MODULE_PSA_FANCYCRYPT
|
||
* bool
|
||
* @endcode
|
||
*
|
||
* If the implementation has any dependencies, we can select them in this Kconfig file:
|
||
* @code
|
||
* config MODULE_PSA_FANCYCRYPT_HASHES_SHA_256
|
||
* bool
|
||
* depends on MODULE_PSA_CRYPTO
|
||
* select MODULE_PSA_FANCYCRYPT
|
||
* select MODULE_PSA_FANCYCRYPT_HASHES_COMMON
|
||
* select MODULE_PSA_FANCYCRYPT_ERROR_CONVERSION
|
||
* @endcode
|
||
*
|
||
* In `pkg/fancycrypt/Kconfig` we need to add the line
|
||
* @code
|
||
* rsource "psa_fancycrypt/Kconfig"
|
||
* @endcode
|
||
* at the bottom.
|
||
*
|
||
* #### Telling PSA Crypto about it
|
||
* To be able to choose `fancycrypt` as a PSA backend, we need to add the option to the Kconfig
|
||
* and Makefiles of the PSA Crypto Module.
|
||
*
|
||
* In `sys/psa_crypto/` we need to modify `Kconfig.asymmetric`, `sys/psa_crypto/Kconfig.hashes`,
|
||
* `Makefile.dep` and `Makefile.include`.
|
||
*
|
||
* To `Kconfig.asymmetric` we need to add
|
||
* @code
|
||
* config MODULE_PSA_ASYMMETRIC_ECC_P256R1_BACKEND_FANCYCRYPT
|
||
* bool "FancyCrypt Package"
|
||
* select PACKAGE_FANCYCRYPT
|
||
* select MODULE_PSA_FANCYCRYPT_P256
|
||
* @endcode
|
||
* This will expose FancyCrypt as a backend option in PSA and then enable all the necessary
|
||
* features, when users select it.
|
||
* You need to do the same thing for the hash operation in `Kconfig.hashes`.
|
||
*
|
||
* To achieve the same thing with Makefiles we need to do this in two places:
|
||
* In `Makefile.include` there are some existing pseudomodules for asymmetric crypto and hashes.
|
||
* There we need to create the backend modules for FancyCrypt by adding
|
||
*
|
||
* @code
|
||
* PSEUDOMODULES += psa_asymmetric_ecc_p256r1_backend_fancycrypt
|
||
* @endcode
|
||
*
|
||
* and
|
||
*
|
||
* @code
|
||
* PSEUDOMODULES += psa_hash_sha_256_backend_fancycrypt
|
||
* @endcode
|
||
*
|
||
* The automatic module selection happens in `Makefile.dep`. To the place where exiting P256 curves
|
||
* and hashes are selected we add cases for our backend modules:
|
||
*
|
||
* @code
|
||
* ifneq (,$(filter psa_asymmetric_ecc_p256r1_backend_fancycrypt,$(USEMODULE)))
|
||
* USEPKG += fancycrypt
|
||
* USEMODULE += psa_fancycrypt
|
||
* USEMODULE += psa_fancycrypt_p256
|
||
* endif
|
||
* @endcode
|
||
*
|
||
* Now you should be able to select your package as a backend for PSA Crypto and use it to perform
|
||
* operations.
|
||
*
|
||
* ### Case Example – A Hardware Driver {#porting-hardware}
|
||
* The first steps of porting a hardware driver are the same as for the software library.
|
||
* Only we skip the last part where we add the modules to the PSA Crypto Kconfig and Makefiles
|
||
* and do something else instead.
|
||
*
|
||
* Hardware drivers are treated a little differently, mostly because they are tied to a specific
|
||
* platform and users can not just choose a different driver for their accelerator.
|
||
* Therefore we just want PSA Crypto to automatically use this driver whenever it runs on the
|
||
* corresponding platform, which means that we have to add some additional options and features,
|
||
* not only to the driver but also to the CPU it belongs to.
|
||
* A good example for this is the [CryptoCell 310 driver](#pkg_driver_cryptocell_310) for the
|
||
* accelerator on the [nRF52840 CPU](#cpu_nrf52).
|
||
*
|
||
* Now, let's say we have a CPU called `myCPU` with an on-chip accelerator called
|
||
* `speedycrypt`. Let's say that `speedycrypt` provides hashes and ECC curves.
|
||
* The vendor provides a driver, which we already have included in RIOT as a package.
|
||
* Also we've followed the steps in the [glue code section](#glue-code) and provide a folder called
|
||
* `pkg/driver_speedycrypt/psa_speedycrypt` with the required wrapper files.
|
||
* We have also added the module names in a Kconfig file and in the Makefiles.
|
||
*
|
||
* #### Telling PSA Crypto about it
|
||
* This is where we diverge from the software library example. If you take a look at the available
|
||
* backends in PSA, you'll notice one with the postfix `*_BACKEND_PERIPH` for each available
|
||
* algorithm. **Periph** here is short for *peripheral hardware accelerator*.
|
||
* The `*_BACKEND_PERIPH` modules depend on the presence of such an accelerator. They are a generic
|
||
* module for all crypto hardware accelerators and will automatically resolve to the driver that is
|
||
* associated with the available accelerator.
|
||
*
|
||
* Before we're able to use it we need to tell RIOT that those hardware features exist for
|
||
* our `myCPU` (see `cpu/nrf52/Kconfig` and `cpu/nrf52/Makefile.features` as an example).
|
||
* In `cpu/myCPU` we add all the provided features as shown below.
|
||
*
|
||
* Files we need to touch:
|
||
* - `cpu/myCPU/Makefile.features`
|
||
* - `cpu/myCPU/Kconfig`
|
||
* - `cpu/myCPU/periph/Makefile.dep`
|
||
* - `cpu/myCPU/periph/Kconfig`
|
||
* - When defining new features: `RIOT/kconfigs/Kconfig.features`
|
||
*
|
||
* **cpu/myCPU/Makefile.features:**
|
||
* @code
|
||
* FEATURES_PROVIDED += periph_speedycrypt // General feature for the accelerator
|
||
* FEATURES_PROVIDED += periph_hash_sha_256
|
||
* FEATURES_PROVIDED += periph_ecc_p256r1
|
||
* @endcode
|
||
*
|
||
* **cpu/myCPU/Kconfig:**
|
||
* @code
|
||
* config CPU_FAM_MYCPU
|
||
* bool
|
||
* select CPU_SOME_FEATURES
|
||
* ...
|
||
* select HAS_PERIPH_HASH_SHA_256
|
||
* select HAS_PERIPH_ECC_P256R1
|
||
* select HAS_PERIPH_SPEEDYCRYPT
|
||
* @endcode
|
||
* The `HAS_PERIPH_*` symbols are defined in ``. If your device
|
||
* provides capabilities that are not yet defined, you can add them to that file.
|
||
*
|
||
* Next we need to define selectable modules for this in the `cpu/myCPU/periph` folder, which
|
||
* then automatically enable the driver. An example for this is `cpu/nrf52/periph`.
|
||
* We add the following to the `cpu/myCPU/periph/Kconfig` file and `cpu/myCPU/periph/Makefile.dep`:
|
||
*
|
||
* **cpu/myCPU/periph/Makefile.dep:**
|
||
* @code
|
||
* ifneq (,$(filter periph_hash_sha_256,$(USEMODULE)))
|
||
* USEPKG += driver_speedycrypt
|
||
* USEMODULE += psa_speedycrypt_hashes_sha256
|
||
* endif
|
||
* @endcode
|
||
*
|
||
* **cpu/myCPU/periph/Kconfig:**
|
||
* @code
|
||
* config MODULE_PERIPH_FANCYCRYPT
|
||
* bool
|
||
* depends on HAS_PERIPH_FANCYCRYPT
|
||
* select PACKAGE_DRIVER_FANCYCRYPT
|
||
*
|
||
* config MODULE_PERIPH_HASH_SHA_256
|
||
* bool
|
||
* depends on HAS_PERIPH_HASH_SHA_256
|
||
* select MODULE_PERIPH_SPEEDYCRYPT
|
||
* select MODULE_PSA_SPEEDYCRYPT_HASHES_SHA256
|
||
* @endcode
|
||
*
|
||
* Here we basically say "If the user chooses the `periph_hash_sha_256 module`, also select the
|
||
* `periph_speedycrypt` feature, which will then enable the speedycrypt driver". Of course you need
|
||
* to do this for all your available features.
|
||
*
|
||
* Now, if you build PSA Crypto with default configurations, it should automatically detect that
|
||
* your board has a hardware accelerator for hashes and ECC operations and build the hardware
|
||
* driver as a backend.
|
||
*
|
||
* ### Case Example – A Secure Element Driver {#porting-secure-elements}
|
||
* Secure elements (SEs) are handled almost completely separate from the other backends. When we use
|
||
* software libraries or hardware drivers, we only build one implementation per algorithm.
|
||
* When it comes to secure elements we want to be able to build them in addition to the other
|
||
* backends and we may want to connect and use more than one of them at the same time.
|
||
* Another difference is that when using software libraries and hardware drivers, PSA handles the
|
||
* storage of key material. When using SEs, keys are stored on the SE, which means, we need
|
||
* additional functionality for the key management.
|
||
*
|
||
* An existing example in RIOT is the Microchip ATECCX08A device family, whose driver can be found
|
||
* in `pkg/cryptoauthlib`.
|
||
*
|
||
* PSA Crypto has an integrated SE driver registry, which stores all registered drivers in a list.
|
||
* When an application calls a cryptographic operation that's supposed to be performed by a secure
|
||
* element, the registry will find the correct driver in the list and PSA will invoke the operation.
|
||
* Each driver is stored with a context that contains persistent as well as transient driver data.
|
||
* Transient driver data can be anything the driver needs to function. Persistent data is supposed
|
||
* to be used to keep track of how many keys are stored on the device and if there is still some
|
||
* free space available.
|
||
*
|
||
* @note Currently PSA does not support persistent storage, so the persistent driver data
|
||
* is not really persistent, yet. Once persistent storage is implemented, this data
|
||
* will be stored, so the implementation can find already existing keys again after
|
||
* a reboot.
|
||
*
|
||
* For this example we integrate an imaginary SE called `superSE`, which comes with a driver called
|
||
* `superSE_lib`. Again, we assume that we have already added the driver as a package in RIOT and it
|
||
* can be found at `pkg/superse_lib`.
|
||
*
|
||
* #### Adding the Glue Code
|
||
* Secure element drivers need to implement a different API than the other backends. It is defined
|
||
* [here](#sys_psa_crypto_se_driver).
|
||
* In our package folder we now create a new folder called `psa_superse_driver` and add a source
|
||
* file called `psa_superse_lib_driver.c`. Here we now implement glue code for all the cryptographic
|
||
* operations our SE supports.
|
||
*
|
||
* You will notice that the SE interface also provides some key management functions. This is
|
||
* because keys are stored on the device and PSA can not access the memory and key data itself,
|
||
* but needs to tell the driver to do it.
|
||
*
|
||
* ### Operation Contexts
|
||
* Some operations need driver specific contexts. For secure elements these are wrapped in types
|
||
* defined in `crypto_contexts.h` (currently only `psa_se_cipher_context_t` is supported).
|
||
* In this header file add operation contexts that belong to your driver to the available SE
|
||
* context unions as shown in the example below:
|
||
*
|
||
* @code
|
||
* typedef struct {
|
||
* union driver_context {
|
||
* unsigned dummy;
|
||
* #if IS_USED(MODULE_PSA_SECURE_ELEMENT_ATECCX08A) || defined(DOXYGEN)
|
||
* atca_aes_cbc_ctx_t atca_aes_cbc;
|
||
* #endif
|
||
* #if IS_USED(MODULE_PSA_SECURE_ELEMENT_SUPERSE) || defined(DOXYGEN)
|
||
* superse_cipher_ctx_t superse_aes_cbc;
|
||
* #endif
|
||
* } drv_ctx;
|
||
* } psa_se_cipher_context_t;
|
||
* @endcode
|
||
*
|
||
* #### Allocation
|
||
* The first thing PSA will do, when an application creates a key on an SE, is ask the driver to
|
||
* find a free key slot on the device. This is what the `allocate` function is for. How exactly
|
||
* the slot is allocated, depends on the driver.
|
||
* It may be possible to query that information directly from the device. If that is not possible,
|
||
* we can use the persistent data stored in the driver context. An example for this can be
|
||
* found in `pkg/cryptoauthlib/psa_atca_driver/psa_atca_se_driver.c`.
|
||
* This example requires the user to provide information about the configurations for each key slot,
|
||
* which is then stored in the persistent driver data and used for key management (for a better
|
||
* description read [Using Cryptoauthlib as a backend for PSA Crypto](#psa-cryptoauthlib)).
|
||
* At this point you can decide what the best approach for your device is.
|
||
*
|
||
* The `allocate` function should then return some reference to the slot it has allocated
|
||
* for the key (possibly a pointer or a slot number). Next PSA Crypto will invoke the `import`
|
||
* or `generate` function to store a key.
|
||
*
|
||
* #### Using Persistent Data
|
||
* When you want to use persistent data to keep track of keys, you should utilize the
|
||
* `psa_se_config_t` structure, which is declared in `crypto_se_config.h`.
|
||
* You can define a structure that can hold your device configuration and make sure it is available
|
||
* then your SE is used.
|
||
*
|
||
* #### Making the Methods Available
|
||
* At the bottom of the wrapper code, define structures with pointers to the available methods.
|
||
* For example if you have implemented a `superse_allocate` and `superse_generate_key` function,
|
||
* you need to add a `psa_drv_se_key_management_t` structure as shown below. Fill the unimplemented
|
||
* methods with `NULL` pointers.
|
||
* The last structure should be a `psa_drv_se_t` struct containing pointers to the other structures.
|
||
* That one will be stored during driver registration to get access to all the implemented
|
||
* functions.
|
||
*
|
||
* @code {.c}
|
||
* static psa_drv_se_key_management_t superse_key_management = {
|
||
* .p_allocate = superse_allocate,
|
||
* .p_validate_slot_number = NULL,
|
||
* .p_import = NULL,
|
||
* .p_generate = superse_generate_key,
|
||
* .p_destroy = NULL,
|
||
* .p_export = NULL,
|
||
* .p_export_public = NULL
|
||
* };
|
||
*
|
||
* psa_drv_se_t superse_methods = {
|
||
* .hal_version = PSA_DRV_SE_HAL_VERSION,
|
||
* .persistent_data_size = 0,
|
||
* .p_init = NULL,
|
||
* .key_management = &superse_key_management,
|
||
* .mac = NULL,
|
||
* .cipher = NULL,
|
||
* .aead = NULL,
|
||
* .asymmetric = NULL,
|
||
* .derivation = NULL
|
||
* };
|
||
* @endcode
|
||
*
|
||
* You should do this for all available functions. The structures for the functions are
|
||
* declared in `sys/psa_crypto/include/psa_crypto_se_driver.h`.
|
||
*
|
||
* #### Driver Registration
|
||
* At start-up all secure element drivers need to be registered with the PSA SE management module.
|
||
* This happens by calling `psa_register_secure_element()` during the automatic driver
|
||
* initialization in RIOT.
|
||
* When you added support for our device to RIOT, you should have implemented an
|
||
* `auto_init_<device>` function, which initializes the connected devices.
|
||
* In this function, after initializing a device, you should call `psa_register_secure_element()`
|
||
* and pass the device's location value, and pointers to the `psa_drv_se_t` structure,
|
||
* the persistent data and some device specific context.
|
||
* An example implementation of this can be seen in `sys/auto_init/security/auto_init_atca.c`.
|
||
*
|
||
* #### Telling PSA Crypto about it
|
||
* To be able to choose our `superSE` during configuration, we need to define the corresponding
|
||
* modules in the Kconfig files and Makefiles.
|
||
*
|
||
* To `pkg/super_se_lib/Kconfig` we add something like
|
||
* @code
|
||
* config MODULE_PSA_SUPERSE_DRIVER
|
||
* bool
|
||
* depends on PACKAGE_SUPERSE_LIB
|
||
* default y if MODULE_PSA_CRYPTO
|
||
* select PSA_KEY_MANAGEMENT
|
||
* @endcode
|
||
* This tells the build system that whenever this driver and PSA Crypto are used at the same time,
|
||
* the wrapper and the PSA key management module are needed, too.
|
||
*
|
||
* To `sys/psa_crypto/psa_se_mgmt/Kconfig` we add a menu for the SE like so:
|
||
* @code
|
||
* menuconfig MODULE_PSA_SECURE_ELEMENT_SUPERSE
|
||
* bool "Our Vendor's SuperSE"
|
||
* select PACKAGE_SUPERSE_LIB
|
||
* depends on <whatever protocol is needed for communication, e.g. HAS_PERIPH_I2C>
|
||
* help
|
||
* <Some helpful information about this module>
|
||
* @endcode
|
||
* This makes our driver selectable whenever an application configuration selects the PSA secure
|
||
* element module.
|
||
*
|
||
* As described in the [Configuration Section](#configuration-keys), references to keys on secure
|
||
* elements are stored by PSA in a different type of key slot than other keys.
|
||
* The slot for protected keys usually only contains a slot number or address and not the actual
|
||
* key, which requires a lot less memory space.
|
||
*
|
||
* **BUT:** If your secure element supports asymmetric cryptography and exports a public key part
|
||
* during key generation, that key part must be stored somewhere. So when you choose an
|
||
* asymmetric operation, the protected key slots will have the space to store a public
|
||
* key.
|
||
*
|
||
* #### Dependencies
|
||
* Secure Element operations also depend on the PSA modules. E.g. when you want to use an ECC
|
||
* operation, you need to make sure that you also build the asymmetric PSA functions.
|
||
*
|
||
* For this we need to add the following to the `superSE` menu:
|
||
* @code
|
||
* config MODULE_PSA_SECURE_ELEMENT_SUPERSE_ECC_P256
|
||
* bool "Our Vendor's Elliptic Curve P256"
|
||
* select PSA_KEY_SIZE_256
|
||
* select MODULE_PSA_ASYMMETRIC
|
||
* depends on MODULE_PSA_SECURE_ELEMENT_SUPERSE
|
||
* @endcode
|
||
* This tells us, what size a key slot should have to store the public key. If your SE supports
|
||
* other curves, you need to modify this accordingly or add more of them.
|
||
*
|
||
* Now we need to add the same to the Makefiles. In `Makefile.include` we add the source file path
|
||
* and the PSA include folders and define the new available pseudomodules:
|
||
* @code
|
||
* ifneq (,$(filter psa_crypto,$(USEMODULE)))
|
||
* DIRS += $(RIOTPKG)/superse_lib/psa_superse_driver
|
||
* INCLUDES += -I$(RIOTBASE)/sys/psa_crypto/include
|
||
* PSEUDOMODULES += psa_secure_element_superse
|
||
* PSEUDOMODULES += psa_secure_element_superse_ecc_p256
|
||
* endif
|
||
* @endcode
|
||
*
|
||
* In `Makefile.dep` we automatically add required modules when PSA Crypto and the ECC curve
|
||
* module are chosen:
|
||
* @code
|
||
* ifneq (,$(filter psa_crypto,$(USEMODULE)))
|
||
* USEMODULE += psa_superse_driver
|
||
* endif
|
||
*
|
||
* ifneq (,$(filter psa_secure_element_superse_ecc_p256, $(USEMODULE)))
|
||
* USEMODULE += psa_asymmetric
|
||
* endif
|
||
* @endcode
|
||
* This needs to be done for all other supported operations (e.g. ATECCX08 operations in
|
||
* `pkg/cryptoauthlib/Makefile.include`, `pkg/cryptoauthlib/Makefile.dep` and
|
||
* `sys/psa_crypto/psa_se_mgmt/Kconfig`. Now the secure element should be available for use
|
||
* with PSA Crypto.
|
||
*/
|