Skip to content

Commit

Permalink
crypto: provide incremental by-subsystem initialization for the library
Browse files Browse the repository at this point in the history
  • Loading branch information
athoelke committed Sep 4, 2024
1 parent 29bf009 commit a4b7323
Show file tree
Hide file tree
Showing 14 changed files with 253 additions and 78 deletions.
10 changes: 10 additions & 0 deletions doc/crypto/api.db/psa/crypto.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
typedef /* implementation-defined type */ psa_aead_operation_t;
typedef uint32_t psa_algorithm_t;
typedef /* implementation-defined type */ psa_cipher_operation_t;
typedef uint32_t psa_crypto_subsystem_t;
typedef uint8_t psa_dh_family_t;
typedef uint8_t psa_ecc_family_t;
typedef /* implementation-defined type */ psa_hash_operation_t;
Expand Down Expand Up @@ -207,8 +208,16 @@ typedef struct psa_custom_key_parameters_t {
/* implementation-defined value */
#define PSA_CIPHER_UPDATE_OUTPUT_SIZE(key_type, alg, input_length) \
/* implementation-defined value */
#define PSA_CRYPTO_ALL_SUBSYSTEMS /* implementation-defined value */
#define PSA_CRYPTO_API_VERSION_MAJOR 1
#define PSA_CRYPTO_API_VERSION_MINOR 3
#define PSA_CRYPTO_SUBSYSTEM_ACCELERATORS /* implementation-defined value */
#define PSA_CRYPTO_SUBSYSTEM_BUILTIN_KEYS /* implementation-defined value */
#define PSA_CRYPTO_SUBSYSTEM_COMMUNICATION /* implementation-defined value */
#define PSA_CRYPTO_SUBSYSTEM_KEYS /* implementation-defined value */
#define PSA_CRYPTO_SUBSYSTEM_RANDOM /* implementation-defined value */
#define PSA_CRYPTO_SUBSYSTEM_SECURE_ELEMENTS /* implementation-defined value */
#define PSA_CRYPTO_SUBSYSTEM_STORAGE /* implementation-defined value */
#define PSA_CUSTOM_KEY_PARAMETERS_INIT { 0 }
#define PSA_DH_FAMILY_RFC7919 ((psa_dh_family_t) 0x03)
#define PSA_ECC_FAMILY_BRAINPOOL_P_R1 ((psa_ecc_family_t) 0x30)
Expand Down Expand Up @@ -498,6 +507,7 @@ psa_status_t psa_copy_key(psa_key_id_t source_key,
const psa_key_attributes_t * attributes,
psa_key_id_t * target_key);
psa_status_t psa_crypto_init(void);
psa_status_t psa_crypto_init_subsystem(psa_crypto_subsystem_t subsystem);
psa_status_t psa_destroy_key(psa_key_id_t key);
psa_status_t psa_export_key(psa_key_id_t key,
uint8_t * data,
Expand Down
2 changes: 1 addition & 1 deletion doc/crypto/api/keys/attributes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ Managing key attributes
.. retval:: PSA_ERROR_DATA_CORRUPT
.. retval:: PSA_ERROR_DATA_INVALID
.. retval:: PSA_ERROR_BAD_STATE
The library requires initializing by a call to `psa_crypto_init()`.
The library requires initializing. See :secref:`library-init`.

This function first resets the attribute object as with `psa_reset_key_attributes()`. It then copies the attributes of the given key into the given attribute object.

Expand Down
14 changes: 7 additions & 7 deletions doc/crypto/api/keys/management.rst
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ When creating a key, the attributes for the new key are specified in a `psa_key_
.. retval:: PSA_ERROR_DATA_INVALID
.. retval:: PSA_ERROR_CORRUPTION_DETECTED
.. retval:: PSA_ERROR_BAD_STATE
The library requires initializing by a call to `psa_crypto_init()`.
The library requires initializing, see :secref:`library-init`.

The key is extracted from the provided ``data`` buffer. Its location, policy, and type are taken from ``attributes``.

Expand Down Expand Up @@ -219,7 +219,7 @@ When creating a key, the attributes for the new key are specified in a `psa_key_
.. retval:: PSA_ERROR_DATA_CORRUPT
.. retval:: PSA_ERROR_DATA_INVALID
.. retval:: PSA_ERROR_BAD_STATE
The library requires initializing by a call to `psa_crypto_init()`.
The library requires initializing, see :secref:`library-init`.

The key is generated randomly. Its location, policy, type and size are taken from ``attributes``.

Expand Down Expand Up @@ -384,7 +384,7 @@ When creating a key, the attributes for the new key are specified in a `psa_key_
.. retval:: PSA_ERROR_DATA_INVALID
.. retval:: PSA_ERROR_CORRUPTION_DETECTED
.. retval:: PSA_ERROR_BAD_STATE
The library requires initializing by a call to `psa_crypto_init()`.
The library requires initializing, see :secref:`library-init`.

Copy key material from one location to another. Its location is taken from ``attributes``, its policy is the intersection of the policy in ``attributes`` and the source key policy, and its type and size are taken from the source key.

Expand Down Expand Up @@ -438,7 +438,7 @@ Key destruction
.. retval:: PSA_ERROR_CORRUPTION_DETECTED
An unexpected condition which is not a storage corruption or a communication failure occurred. The cryptoprocessor might have been compromised.
.. retval:: PSA_ERROR_BAD_STATE
The library requires initializing by a call to `psa_crypto_init()`.
The library requires initializing, see :secref:`library-init`.

This function destroys a key from both volatile memory and, if applicable, non-volatile storage. Implementations must make a best effort to ensure that that the key material cannot be recovered.

Expand Down Expand Up @@ -468,7 +468,7 @@ Key destruction
.. retval:: PSA_ERROR_DATA_INVALID
.. retval:: PSA_ERROR_CORRUPTION_DETECTED
.. retval:: PSA_ERROR_BAD_STATE
The library requires initializing by a call to `psa_crypto_init()`.
The library requires initializing, see :secref:`library-init`.

For keys that have been created with the `PSA_KEY_USAGE_CACHE` usage flag, an implementation is permitted to make additional copies of the key material that are not in storage and not for the purpose of ongoing operations.

Expand Down Expand Up @@ -533,7 +533,7 @@ Key export
.. retval:: PSA_ERROR_DATA_INVALID
.. retval:: PSA_ERROR_INSUFFICIENT_MEMORY
.. retval:: PSA_ERROR_BAD_STATE
The library requires initializing by a call to `psa_crypto_init()`.
The library requires initializing, see :secref:`library-init`.

The output of this function can be passed to `psa_import_key()` to create an equivalent object.

Expand Down Expand Up @@ -585,7 +585,7 @@ Key export
.. retval:: PSA_ERROR_DATA_INVALID
.. retval:: PSA_ERROR_INSUFFICIENT_MEMORY
.. retval:: PSA_ERROR_BAD_STATE
The library requires initializing by a call to `psa_crypto_init()`.
The library requires initializing, see :secref:`library-init`.

The output of this function can be passed to `psa_import_key()` to create an object that is equivalent to the public key.

Expand Down
183 changes: 173 additions & 10 deletions doc/crypto/api/library/library.rst
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,37 @@ API version
Library initialization
----------------------

It is recommended that applications initialize the |API| implementation, before calling any other function, except as otherwise indicated.
This is typically achieved by calling `psa_crypto_init()`.

Some implementations provide the ability to selectively initialize a subset of the functionality, using calls to `psa_crypto_init_subsystem()`.
For example, this permits use cases such as early-stage bootloaders, that need to decrypt or authenticate firmware, where it is unnecessary to wait for an RNG to collect enough entropy.
In these implementations, calling `psa_crypto_init()` is equivalent to calling `psa_crypto_init_subsystem()` for all available subsystems.

Applications are permitted to call these functions more than once.
Once a subsystem is successfully initialized, subsequent calls to initialize the same subsystem are guaranteed to succeed.

If the application calls any function that returns a :code:`psa_status_t` result code before initializing the related subsystems, the following will occur:

* If initialization of the library is essential for secure operation of the function, the implementation must return :code:`PSA_ERROR_BAD_STATE` or other appropriate error.

* If failure to initialize the library does not compromise the security of the function, the implementation must either provide the expected result for the function, or return :code:`PSA_ERROR_BAD_STATE` or other appropriate error.

.. note::

The following scenarios are examples where an implementation can require that the library has been initialized:

* A client-server implementation, in which `psa_crypto_init()`, or :code:`psa_crypto_init_subsystem(PSA_CRYPTO_SUBSYSTEM_COMMUNICATION)`, establishes the communication with the server.
No key management or cryptographic operation can be performed until this is done.

* An implementation in which `psa_crypto_init()`, or :code:`psa_crypto_init_subsystem(PSA_CRYPTO_SUBSYSTEM_RANDOM)`, initializes the random bit generator, and no operations that require the RNG can be performed until this is done.
For example, random data, key, IV, or nonce generation; randomized signature or encryption; and algorithms that are implemented with blinding.

.. warning::

The set of functions that depend on successful initialization of specific subsystems, is :scterm:`IMPLEMENTATION DEFINED`.
Applications that rely on calling functions before initializing the library might not be portable to other implementations.

.. function:: psa_crypto_init

.. summary::
Expand All @@ -52,24 +83,156 @@ Library initialization
.. retval:: PSA_ERROR_COMMUNICATION_FAILURE
.. retval:: PSA_ERROR_CORRUPTION_DETECTED
.. retval:: PSA_ERROR_INSUFFICIENT_ENTROPY
.. retval:: PSA_ERROR_INSUFFICIENT_STORAGE
.. retval:: PSA_ERROR_HARDWARE_FAILURE
.. retval:: PSA_ERROR_STORAGE_FAILURE
.. retval:: PSA_ERROR_DATA_INVALID
.. retval:: PSA_ERROR_DATA_CORRUPT

It is recommended that applications call this function before calling any other function in this module.
It is recommended that applications call this function before calling any other function in this module, except as otherwise indicated.

Applications are permitted to call this function more than once. Once a call succeeds, subsequent calls are guaranteed to succeed.

If the application calls any function that returns a :code:`psa_status_t` result code before calling `psa_crypto_init()`, the following will occur:
For finer control over initialization, see `psa_crypto_init_subsystem()`.

* If initialization of the library is essential for secure operation of the function, the implementation must return :code:`PSA_ERROR_BAD_STATE` or other appropriate error.
See also :secref:`library-init`.

* If failure to initialize the library does not compromise the security of the function, the implementation must either provide the expected result for the function, or return :code:`PSA_ERROR_BAD_STATE` or other appropriate error.
.. typedef:: uint32_t psa_crypto_subsystem_t

.. note::
.. summary::
Encoding of a subsystem of the |API| implementation.

This type is used to specify implementation subsystems in a call to `psa_crypto_init_subsystem()`.
Values of this type are ``PSA_CRYPTO_SUBSYSTEM_xxx`` constants, or a bitwise-or of two or more of them.

.. admonition:: Implementation note

An implementation can define additional subsystem identifier values for use with `psa_crypto_init_subsystem()`.

.. macro:: PSA_CRYPTO_SUBSYSTEM_COMMUNICATION
:definition: /* implementation-defined value */
.. summary::
Crypto subsystem identifier for the communication with the server, if this is a client that communicates with a server where the key store is located.

In a client-server implementation, initializing this subsystem is necessary before any API function other than library initialization, deinitialization and functions accessing local data structures such as key attributes.

In a library implementation, initializing this subsystem has no effect, and always succeeds.

.. macro:: PSA_CRYPTO_SUBSYSTEM_KEYS
:definition: /* implementation-defined value */
.. summary::
Crypto subsystem identifier for the key store in memory.

Initializing this subsystem allows creating, accessing and destroying volatile keys in the default location, that is, keys with the lifetime `PSA_KEY_LIFETIME_VOLATILE`.

Persistent keys also require `PSA_CRYPTO_SUBSYSTEM_STORAGE`.
Keys in other locations also require `PSA_CRYPTO_SUBSYSTEM_SECURE_ELEMENTS`.

The following scenarios are examples where an implementation can require that the library has been initialized by calling `psa_crypto_init()`:

* A client-server implementation, in which `psa_crypto_init()` establishes the communication with the server. No key management or cryptographic operation can be performed until this is done.
.. macro:: PSA_CRYPTO_SUBSYSTEM_STORAGE
:definition: /* implementation-defined value */
.. summary::
Crypto subsystem identifier for access to keys in storage.

* An implementation in which `psa_crypto_init()` initializes the random bit generator, and no operations that require the RNG can be performed until this is done. For example, random data, key, IV, or nonce generation; randomized signature or encryption; and algorithms that are implemented with blinding.
Initializing this subsystem and the `PSA_CRYPTO_SUBSYSTEM_KEYS` subsystem allows creating, accessing, and destroying persistent keys.

Persistent keys in secure elements also require `PSA_CRYPTO_SUBSYSTEM_SECURE_ELEMENTS`.

.. macro:: PSA_CRYPTO_SUBSYSTEM_ACCELERATORS
:definition: /* implementation-defined value */
.. summary::
Crypto subsystem identifier for accelerator drivers.

Initializing this subsystem results in initialization of all registered accelerator drivers.

Initializing this subsystem allows cryptographic operations that are implemented via an accelerator driver.

.. macro:: PSA_CRYPTO_SUBSYSTEM_SECURE_ELEMENTS
:definition: /* implementation-defined value */
.. summary::
Crypto subsystem identifier for secure element drivers.

Initializing this subsystem results in initialization of all registered secure element drivers.

Initializing this subsystem as well as `PSA_CRYPTO_SUBSYSTEM_KEYS` allows creating, accessing, and destroying keys in a secure element. That is, keys whose location is not `PSA_KEY_LOCATION_LOCAL_STORAGE`.

.. macro:: PSA_CRYPTO_SUBSYSTEM_RANDOM
:definition: /* implementation-defined value */
.. summary::
Crypto subsystem identifier for the random generator.

Initializing this subsystem initializes all registered entropy drivers, and accesses the registered entropy sources.

Initializing this subsystem is necessary for `psa_generate_random()`, `psa_generate_key()`, and some operations using private or secret keys.

It is guaranteed that the following operations do not to require this subsystem:

* Hash operations.
* Signature verification operations.

Is it :scterm:`implementation defined` whether other operations require the initialization of this subsystem.

.. macro:: PSA_CRYPTO_SUBSYSTEM_BUILTIN_KEYS
:definition: /* implementation-defined value */
.. summary::
Crypto subsystem identifier for access to built-in keys.

Initializing this subsystem as well as `PSA_CRYPTO_SUBSYSTEM_KEYS` allows access to built-in keys.

.. macro:: PSA_CRYPTO_ALL_SUBSYSTEMS
:definition: /* implementation-defined value */
.. summary::
Crypto subsystem identifier for all available subsystems.

Using this value in a call to `psa_crypto_init_subsystem()` is equivalent to calling `psa_crypto_init()`.

.. function:: psa_crypto_init_subsystem

.. summary::
Partial library initialization.

.. param:: psa_crypto_subsystem_t subsystem
The subsystem, or set of subsystems, to initialize.
This must be one of the ``PSA_CRYPTO_SUBSYSTEM_xxx`` values, one of the implementation-specific subsystem values, or a bitwise-or of them.

.. return:: psa_status_t
.. retval:: PSA_SUCCESS
Success.
.. retval:: PSA_ERROR_INVALID_ARGUMENT
``subsystem`` is not a bitwise-or of one or more of the crypto subsystem identifier values.
These values can be defined in this specification or by the implementation.
.. retval:: PSA_ERROR_INSUFFICIENT_MEMORY
.. retval:: PSA_ERROR_COMMUNICATION_FAILURE
.. retval:: PSA_ERROR_CORRUPTION_DETECTED
.. retval:: PSA_ERROR_INSUFFICIENT_ENTROPY
.. retval:: PSA_ERROR_INSUFFICIENT_STORAGE
.. retval:: PSA_ERROR_HARDWARE_FAILURE
.. retval:: PSA_ERROR_STORAGE_FAILURE
.. retval:: PSA_ERROR_DATA_INVALID
.. retval:: PSA_ERROR_DATA_CORRUPT

Applications may call this function on the same subsystem more than once.
Once a call succeeds, subsequent calls with the same subsystem are guaranteed to succeed.

Initializing a subsystem may initialize other subsystems if the implementations needs them internally.
For example, in a typical client-server implementation, `PSA_CRYPTO_SUBSYSTEM_COMMUNICATION` is required for all other subsystems, and therefore initializing any other subsystem also initializes `PSA_CRYPTO_SUBSYSTEM_COMMUNICATION`.

Calling `psa_crypto_init_subsystem()` with for a subsystem that is not used by the implementation must have no effect, and return :code:`PSA_SUCCESS`.
In effect, this is indicating that there is no further initialization required for this subsystem.

Calling `psa_crypto_init()` is equivalent to calling :code:`psa_crypto_init_subsystem(PSA_CRYPTO_ALL_SUBSYSTEMS)`.

See also :secref:`library-init`.

.. note::

.. warning::
The set of functions that depend on successful initialization of the library is :scterm:`IMPLEMENTATION DEFINED`. Applications that rely on calling functions before initializing the library might not be portable to other implementations.
Multiple subsystems can be initialized in the same call by passing a bitwise-or of ``PSA_CRYPTO_SUBSYSTEM_xxx`` values.
If the initialization of one subsystem fails, it is unspecified whether other requested subsystems are initialized or not.
Loading

0 comments on commit a4b7323

Please sign in to comment.