blob: 004f8bc507d5341fcf145c4d6f98db2b70320222 [file] [log] [blame]
.. _functionality-overview:
Functionality overview
----------------------
This section provides a high-level overview of the functionality provided by the
interface defined in this specification. Refer to the `API definition
<api-reference>` for a detailed description.
`future` describes features that might be included in future versions of this
specification.
Due to the modularity of the interface, almost every part of the library is
optional. The only mandatory function is `psa_crypto_init()`.
Library management
~~~~~~~~~~~~~~~~~~
Applications must call `psa_crypto_init()` to initialize the library before
using any other function.
Key management
~~~~~~~~~~~~~~
Applications always access keys indirectly via an identifier, and can perform
operations using a key without accessing the key material. This allows keys to
be *non-extractable*, where an application can use a key but is not permitted to
obtain the key material. Non-extractable keys are bound to the device, can be
rate-limited and can have their usage restricted by policies.
Each key has a set of attributes that describe the key and the policy for using
the key. A `psa_key_attributes_t` object contains all of the attributes, which
is used when creating a key and when querying key attributes.
Each key has a *lifetime* that determines when the key material is destroyed.
There are two types of lifetimes: `volatile <volatile-keys>` and
`persistent <persistent-keys>`.
.. _volatile-keys:
Volatile keys
^^^^^^^^^^^^^
A *volatile* key exists until it explicitly destroyed with `psa_destroy_key()`
or until the application terminates, which conceptually destroys all of its
volatile keys.
Conceptually, a volatile key is stored in RAM. Volatile keys have the
lifetime `PSA_KEY_LIFETIME_VOLATILE`.
To create a volatile key:
1. Populate a `psa_key_attributes_t` object with the required type, size, policy
and other key attributes.
2. Create the key with `psa_import_key()`, `psa_generate_key()`,
`psa_key_derivation_output_key()` or `psa_copy_key()`. If successful, these
functions output a transient `key identifier <key-ids>`.
To destroy a volatile key, call `psa_destroy_key()` with the key identifier.
.. _persistent-keys:
Persistent keys
^^^^^^^^^^^^^^^
A *persistent* key exists until it explicitly destroyed with `psa_destroy_key()`
or until it is wiped by the reset or destruction of the device.
Each persistent key has a permanent key identifier, which acts as a name for the key.
Within an application, the key identifier corresponds to a single key. The
application specifies the key identifier when the key is created and when
using the key.
Persistent keys can be stored in different storage areas; this is indicated
through different lifetime values. This specification defines a single lifetime
value `PSA_KEY_LIFETIME_PERSISTENT` which corresponds to a default storage
area. Implementations can define alternative lifetime values corresponding to
different storage areas with different retention policies, or to secure elements
with different security characteristics.
To create a persistent key:
1. Populate a `psa_key_attributes_t` object with the keys type, size, policy
and other attributes.
2. In the attributes object, set the desired lifetime and persistent identifier
for the key.
3. Create the key with one of the *key creation functions*:
* `psa_import_key()`
* `psa_generate_key()`
* `psa_key_derivation_output_key()`
* `psa_copy_key()`
If successful, these functions output the `key identifier <key-ids>`
that was specified by the application in step 2.
To access an existing persistent key: use the key identifier in any API that
requires a key.
To remove cached copies of key material for persistent keys created with the
`PSA_KEY_USAGE_CACHE` policy: call `psa_purge_key()` with the key identifier.
To destroy a persistent key: call `psa_destroy_key()` with the key identifier.
Destroying a persistent key permanently removes it from memory and storage.
The key lifetime and identifier are set when the key is created and cannot be
changed without destroying the key first. If the original key permits copying,
then the application can specify a different lifetime for the copy of the key.
.. _key-ids:
Key identifiers
^^^^^^^^^^^^^^^
Key identifiers are integral values that act as permanent names for persistent
keys, or as transient references to volatile keys. Key identifiers use the
`psa_key_id_t` type, and the range of identifier values is divided as follows:
:code:`PSA_KEY_ID_NULL = 0`
Reserved as an invalid key identifier.
:code:`PSA_KEY_ID_USER_MIN - PSA_KEY_ID_USER_MAX`
Applications can freely choose persistent key identifiers in this range.
:code:`PSA_KEY_ID_VENDOR_MIN - PSA_KEY_ID_VENDOR_MAX`
Implementations can define additional persistent key identifiers in this
range, and must allocate any volatile key identifiers from this range.
Key identifiers outside these ranges are reserved for future use.
Key identifiers are output from a successful call to one of
the key creation functions. For persistent keys, this is the same identifier
as the one specified in the key attributes used to create the key.
The key identifier remains valid until it is invalidated by passing it to
`psa_destroy_key()`. A volatile key identifier must not be used after it has been
invalidated.
Valid key identifiers must have distinct values within the same application. If
the implementation provides `caller isolation <isolation>`, then key
identifiers are local to each application. That is, the same key identifier in two
applications corresponds to two different keys.
If an invalid key identifier is provided as a parameter in any function, the
function will return `PSA_ERROR_INVALID_HANDLE`; except for the special case of
calling :code:`psa_destroy_key(PSA_KEY_ID_NULL)`, which has no effect and always
returns `PSA_SUCCESS`.
There must be a matching call to `psa_destroy_key()` for each successful call
to a create a volatile key.
A call to `psa_destroy_key()` destroys the key material, and will cause any active
operations that are using the key to fail. Therefore an application must not
destroy a key while an operation using that key is in progress, unless the
application is prepared to handle a failure of the operation.
Recommendations of minimum standards for key management
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Most implementations provide the following functions:
* `psa_import_key()`. The exceptions are implementations that only give access
to a key or keys that are provisioned by proprietary means, and do not allow
the main application to use its own cryptographic material.
* `psa_get_key_attributes()` and the ``psa_get_key_xxx()`` accessor functions.
They are easy to implement, and it is difficult to write applications and to
diagnose issues without being able to check the metadata.
* `psa_export_public_key()`. This function is usually provided if the
implementation supports any asymmetric algorithm, since public-key
cryptography often requires the delivery of a public key that is associated
with a protected private key.
* `psa_export_key()`. However, highly constrained implementations that are
designed to work only with short-term keys, or only with long-term
non-extractable keys, do not need to provide this function.
Usage policies
~~~~~~~~~~~~~~
All keys have an associated policy that regulates which operations are permitted
on the key. Each key policy is a set of usage flags and a specific algorithm
that is permitted with the key. The policy is part of the key attributes that
are managed by a `psa_key_attributes_t` object.
The usage flags are encoded in a bitmask, which has the type
`psa_key_usage_t`. Four kinds of usage flag can be specified:
* The extractable flag `PSA_KEY_USAGE_EXPORT` determines whether the key
material can be extracted.
* The copyable flag `PSA_KEY_USAGE_COPY` determines whether the key material
can be copied into a new key, which can have a different lifetime or a more
restrictive policy.
* The cacheable flag `PSA_KEY_USAGE_CACHE` determines whether the
implementation is permitted to retain non-essential copies of the
key material in RAM. This policy only applies to persistent keys. See also
:title:`key-material`.
* The other usage flags, for example, `PSA_KEY_USAGE_ENCRYPT` and `PSA_KEY_USAGE_SIGN_MESSAGE`,
determine whether the corresponding operation is permitted on the key.
In addition to the usage bitmask, a policy specifies which algorithm is
permitted with the key. This specification only defines policies that restrict
keys to a single algorithm, which is consistent with both common practice and
security good practice.
A highly constrained implementation might not be able to support all the policies
that can be expressed through this interface. If an implementation cannot create
a key with the required policy, it must return an appropriate error code when
the key is created.
Symmetric cryptography
~~~~~~~~~~~~~~~~~~~~~~
This specification defines interfaces for the following types of symmetric
cryptographic operation:
* Message digests, commonly known as hash functions.
* Message authentication codes (MAC).
* Symmetric ciphers.
* Authenticated encryption with associated data (AEAD).
For each type of symmetric cryptographic operation, the API includes:
* A pair of *single-part* functions. For example, compute and verify, or
encrypt and decrypt.
* A series of functions that permit *multi-part operations*.
Single-part Functions
^^^^^^^^^^^^^^^^^^^^^
Single-part functions are APIs that implement the cryptographic operation in a
single function call. This is the easiest API to use when all of the inputs and
outputs fit into the application memory.
Some use cases involve messages that are too large to be assembled in memory, or
require non-default configuration of the algorithm. These use cases require the
use of a :title:`multi-part operation <multi-part-operations>`.
.. _multi-part-operations:
Multi-part operations
^^^^^^^^^^^^^^^^^^^^^
Multi-part operations are APIs which split a single cryptographic operation into
a sequence of separate steps. This enables fine control over the configuration
of the cryptographic operation, and allows the message data to be processed in
fragments instead of all at once. For example, the following situations require
the use of a multi-part operation:
- Processing messages that cannot be assembled in memory.
- Using a deterministic IV for unauthenticated encryption.
- Providing the IV separately for unauthenticated encryption or decryption.
- Separating the AEAD authentication tag from the cipher text.
Each multi-part operation defines a specific object type to maintain the state
of the operation. These types are implementation-defined. All multi-part
operations follow the same pattern of use:
1. **Allocate:** Allocate memory for an operation object of the appropriate
type. The application can use any allocation strategy: stack, heap, static, etc.
2. **Initialize:** Initialize or assign the operation object by one of the
following methods:
- Set it to logical zero. This is automatic for static and global
variables. Explicit initialization must use the associated
``PSA_xxx_INIT`` macro as the type is implementation-defined.
- Set it to all-bits zero. This is automatic if the object was
allocated with ``calloc()``.
- Assign the value of the associated macro ``PSA_xxx_INIT``.
- Assign the result of calling the associated function
``psa_xxx_init()``.
The resulting object is now *inactive*.
It is an error to initialize an operation object that is in *active* or
*error* states. This can leak memory or other resources.
3. **Setup:** Start a new multi-part operation on an *inactive* operation
object. Each operation object will define one or more setup functions to
start a specific operation.
On success, a setup function will put an operation object into an *active*
state. On failure, the operation object will remain *inactive*.
4. **Update:** Update an *active* operation object. The update function can
provide additional parameters, supply data for processing or generate
outputs.
On success, the operation object remains *active*. On failure, the
operation object will enter an *error* state.
5. **Finish:** To end the operation, call the applicable finishing function.
This will take any final inputs, produce any final outputs, and then
release any resources associated with the operation.
On success, the operation object returns to the *inactive* state. On
failure, the operation object will enter an *error* state.
An operation can be aborted at any stage during its use by calling the
associated ``psa_xxx_abort()`` function. This will release any resources
associated with the operation and return the operation object to the *inactive*
state.
Any error that occurs to an operation while it is in an *active* state will
result in the operation entering an *error* state. The application must call the
associated ``psa_xxx_abort()`` function to release the operation resources and
return the object to the *inactive* state.
Once an operation object is returned to the *inactive* state, it can be reused
by calling one of the applicable setup functions again.
If a multi-part operation object is not initialized before use, the behavior is
undefined.
If a multi-part operation function determines that the operation object is not in
any valid state, it can return `PSA_ERROR_CORRUPTION_DETECTED`.
If a multi-part operation function is called with an operation object in the
wrong state, the function will return `PSA_ERROR_BAD_STATE` and the operation
object will enter the *error* state.
It is safe to move a multi-part operation object to a different memory location,
for example, using a bitwise copy, and then to use the object in the new
location. For example, an application can allocate an operation object on the
stack and return it, or the operation object can be allocated within memory
managed by a garbage collector. However, this does not permit the following
behaviors:
- Moving the object while a function is being called on the object. This is
not safe. See also `concurrency`.
- Working with both the original and the copied operation objects. This
requires cloning the operation, which is only available for hash operations
using `psa_hash_clone()`.
Each type of multi-part operation can have multiple *active* states.
Documentation for the specific operation describes the configuration and update
functions, and any requirements about their usage and ordering.
Message digests (Hashes)
^^^^^^^^^^^^^^^^^^^^^^^^
The single-part hash functions are:
- `psa_hash_compute()` to calculate the hash of a message.
- `psa_hash_compare()` to compare the hash of a message with a reference value.
The `psa_hash_operation_t` `multi-part operation <multi-part-operations>`
allows messages to be processed in fragments:
1. Initialize the `psa_hash_operation_t` object to zero, or by assigning the
value of the associated macro `PSA_HASH_OPERATION_INIT`.
2. Call `psa_hash_setup()` to specify the required hash algorithm, call
`psa_hash_clone()` to duplicate the state of *active* `psa_hash_operation_t`
object, or call `psa_hash_resume()` to restart a hash operation with the
output from a previously suspended hash operation.
3. Call the `psa_hash_update()` function on successive chunks of the message.
4. At the end of the message, call the required finishing function:
- To suspend the hash operation and extract a hash suspend state,
call `psa_hash_suspend()`. The output state can subsequently be used
to resume the hash operation.
- To calculate the digest of a message, call `psa_hash_finish()`.
- To verify the digest of a message against a reference value, call
`psa_hash_verify()`.
To abort the operation or recover from an error, call `psa_hash_abort()`.
Message authentication codes (MACs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The single-part MAC functions are:
- `psa_mac_compute()` to calculate the MAC of a message.
- `psa_mac_verify()` to compare the MAC of a message with a reference value.
The `psa_mac_operation_t` `multi-part operation <multi-part-operations>`
allows messages to be processed in fragments:
1. Initialize the `psa_mac_operation_t` object to zero, or by assigning the
value of the associated macro `PSA_MAC_OPERATION_INIT`.
2. Call `psa_mac_sign_setup()` or `psa_mac_verify_setup()` to specify the
algorithm and key.
3. Call the `psa_mac_update()` function on successive chunks of the message.
4. At the end of the message, call the required finishing function:
- To calculate the MAC of the message, call `psa_mac_sign_finish()`.
- To verify the MAC of the message against a reference value, call
`psa_mac_verify_finish()`.
To abort the operation or recover from an error, call `psa_mac_abort()`.
Encryption and decryption
^^^^^^^^^^^^^^^^^^^^^^^^^
.. note::
The unauthenticated cipher API is provided to implement legacy protocols and
for use cases where the data integrity and authenticity is guaranteed by
non-cryptographic means. It is recommended that newer protocols use
:title:`func-aead`.
The single-part functions for encrypting or decrypting a message using an
unauthenticated symmetric cipher are:
- `psa_cipher_encrypt()` to encrypt a message using an unauthenticated symmetric
cipher. The encryption function generates a random IV. Use the multi-part API
to provide a deterministic IV: this is not secure in general, but
can be secure in some conditions that depend on the algorithm.
- `psa_cipher_decrypt()` to decrypt a message using an unauthenticated symmetric
cipher.
The `psa_cipher_operation_t` `multi-part operation <multi-part-operations>`
permits alternative initialization parameters and allows messages to be
processed in fragments:
1. Initialize the `psa_cipher_operation_t` object to zero, or by assigning the
value of the associated macro `PSA_CIPHER_OPERATION_INIT`.
2. Call `psa_cipher_encrypt_setup()` or `psa_cipher_decrypt_setup()` to specify the
algorithm and key.
3. Provide additional parameters:
- When encrypting data, generate or set an initialization vector (IV),
nonce, or similar initial value such as an initial counter value. To
generate a random IV, which is recommended in most protocols, call
`psa_cipher_generate_iv()`. To set the IV, call `psa_cipher_set_iv()`.
- When decrypting, set the IV or nonce. To set the IV, call
`psa_cipher_set_iv()`.
4. Call the `psa_cipher_update()` function on successive chunks of the message.
5. Call `psa_cipher_finish()` to complete the operation and return any final
output.
To abort the operation or recover from an error, call `psa_cipher_abort()`.
.. _func-aead:
Authenticated encryption (AEAD)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The single-part AEAD functions are:
- `psa_aead_encrypt()` to encrypt a message using an authenticated symmetric
cipher.
- `psa_aead_decrypt()` to decrypt a message using an authenticated symmetric
cipher.
These functions follow the interface recommended by :RFC:`5116`.
The encryption function requires a nonce to be provided. To generate a random
nonce, either call `psa_generate_random()` or use the AEAD multi-part API.
The `psa_aead_operation_t` `multi-part operation <multi-part-operations>`
permits alternative initialization parameters and allows messages to be
processed in fragments:
1. Initialize the `psa_aead_operation_t` object to zero, or by assigning the
value of the associated macro `PSA_AEAD_OPERATION_INIT`.
2. Call `psa_aead_encrypt_setup()` or `psa_aead_decrypt_setup()` to specify the
algorithm and key.
3. Provide additional parameters:
- If the algorithm requires it, call `psa_aead_set_lengths()` to specify the
length of the non-encrypted and encrypted inputs to the operation.
- When encrypting, call either `psa_aead_generate_nonce()` or
`psa_aead_set_nonce()` to generate or set the nonce.
- When decrypting, call `psa_aead_set_nonce()` to set the nonce.
4. Call `psa_aead_update_ad()` zero or more times with fragments of the
non-encrypted additional data.
5. Call `psa_aead_update()` zero or more times with fragments of the plaintext
or ciphertext to encrypt or decrypt.
6. At the end of the message, call the required finishing function:
- To complete an encryption operation, call `psa_aead_finish()` to compute
and return authentication tag.
- To complete a decryption operation, call `psa_aead_verify()` to
compute the authentication tag and verify it against a reference value.
To abort the operation or recover from an error, call `psa_aead_abort()`.
Having a multi-part interface to authenticated encryption raises specific issues.
Multi-part authenticated decryption produces partial results that are not
authenticated. Applications must not use or expose partial results of
authenticated decryption until `psa_aead_verify()` has returned a success
status and must destroy all partial results without revealing them if
`psa_aead_verify()` returns a failure status. Revealing partial results, either directly or indirectly through the applications behavior, can compromise the
confidentiality of all inputs that are encrypted with the same key.
For encryption, some common algorithms cannot be processed in a streaming
fashion. For SIV mode, the whole plaintext must be known before the encryption
can start; the multi-part AEAD API is not meant to be usable with SIV mode. For
CCM mode, the length of the plaintext must be known before the encryption can
start; the application can call the function `psa_aead_set_lengths()` to provide
these lengths before providing input.
.. _key-derivation:
Key derivation
^^^^^^^^^^^^^^
A key derivation encodes a deterministic method to generate a finite stream of
bytes. This data stream is computed by the cryptoprocessor and extracted in
chunks. If two key derivation operations are constructed with the same
parameters, then they produce the same output.
A key derivation consists of two phases:
1. Input collection. This is sometimes known as *extraction*: the operation
extracts information from the inputs to generate a pseudorandom
intermediate secret value.
2. Output generation. This is sometimes known as *expansion*: the operation
expands the intermediate secret value to the desired output length.
The specification defines a `multi-part operation <multi-part-operations>`
API for key derivation that allows for multiple key and non-key outputs to be
extracted from a single derivation operation object.
In an implementation with `isolation <isolation>`, the intermediate
state of the key derivation is not visible to the caller, and if an output of
the derivation is a non-exportable key, then this key cannot be recovered
outside the isolation boundary.
Applications use the `psa_key_derivation_operation_t` type to create key
derivation operations. The operation object is used as follows:
1. Initialize a `psa_key_derivation_operation_t` object to zero or to
`PSA_KEY_DERIVATION_OPERATION_INIT`.
2. Call `psa_key_derivation_setup()` to select a key derivation algorithm.
3. Call the functions `psa_key_derivation_input_bytes()` and
`psa_key_derivation_input_key()`, or `psa_key_derivation_key_agreement()` to
provide the inputs to the key derivation algorithm. Many key derivation
algorithms take multiple inputs; the ``step`` parameter to these functions
indicates which input is being provided. The documentation for each key
derivation algorithm describes the expected inputs for that algorithm and
in what order to pass them.
4. Optionally, call `psa_key_derivation_set_capacity()` to set a limit on the
amount of data that can be output from the key derivation operation.
5. Call `psa_key_derivation_output_key()` to create a derived key, or
`psa_key_derivation_output_bytes()` to export the derived data. These
functions can be called multiple times to read successive output from the key
derivation, until the stream is exhausted when its capacity has been reached.
6. Key derivation does not finish in the same way as other multi-part
operations. Call `psa_key_derivation_abort()` to release the key derivation
operation memory when the object is no longer required.
To recover from an error, call `psa_key_derivation_abort()` to release the key
derivation operation memory.
A key derivation operation cannot be rewound. Once a part of the stream has been
output, it cannot be output again. This ensures that the same part of the output
will not be used for different purposes.
Example of the symmetric cryptography API
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Here is an example of a use case where a master key is used to generate both a
message encryption key and an IV for the encryption, and the derived key and IV
are then used to encrypt a message.
1. Derive the message encryption material from the master key.
1. Initialize a `psa_key_derivation_operation_t` object to zero or to
`PSA_KEY_DERIVATION_OPERATION_INIT`.
2. Call `psa_key_derivation_setup()` with `PSA_ALG_HKDF` as the algorithm.
3. Call `psa_key_derivation_input_key()` with the step
`PSA_KEY_DERIVATION_INPUT_SECRET` and the master key.
4. Call `psa_key_derivation_input_bytes()` with the step
`PSA_KEY_DERIVATION_INPUT_INFO` and a public value that uniquely
identifies the message.
5. Populate a `psa_key_attributes_t` object with the derived message
encryption keys attributes.
6. Call `psa_key_derivation_output_key()` to create the derived message key.
7. Call `psa_key_derivation_output_bytes()` to generate the derived IV.
8. Call `psa_key_derivation_abort()` to release the key derivation operation
memory.
2. Encrypt the message with the derived material.
1. Initialize a `psa_cipher_operation_t` object to zero or to
`PSA_CIPHER_OPERATION_INIT`.
2. Call `psa_cipher_encrypt_setup()` with the derived message encryption key.
3. Call `psa_cipher_set_iv()` using the derived IV retrieved above.
4. Call `psa_cipher_update()` one or more times to encrypt the message.
5. Call `psa_cipher_finish()` at the end of the message.
3. Call `psa_destroy_key()` to clear the generated key.
Asymmetric cryptography
~~~~~~~~~~~~~~~~~~~~~~~
This specification defines functions for asymmetric cryptography, including
asymmetric encryption, asymmetric signature, and two-way key agreement.
Asymmetric encryption
^^^^^^^^^^^^^^^^^^^^^
Asymmetric encryption is provided through the functions
`psa_asymmetric_encrypt()` and `psa_asymmetric_decrypt()`.
Hash-and-sign
^^^^^^^^^^^^^
The signature and verification functions `psa_sign_message()` and
`psa_verify_message()` take a message as one of their inputs and perform a
hash-and-sign algorithm.
The functions `psa_sign_hash()` and `psa_verify_hash()` take a message hash as
one of their inputs. This is useful for signing pre-computed hashes, or for
implementing hash-and-sign using a :ref:`multi-part hash operation <hash-mp>`
before signing the resulting hash. To determine which
hash algorithm to use, call the macro `PSA_ALG_GET_HASH()` on the
corresponding signature algorithm.
Some hash-and-sign algorithms add padding to the message hash before completing
the signing operation. The format of the padding that is used depends on the
algorithm used to construct the signature.
Key agreement
^^^^^^^^^^^^^
This specification defines two functions for a Diffie-Hellman-style key
agreement where each party combines its own private key with the peers public
key.
The recommended approach is to use a `key derivation
operation <key-derivation>` with the `psa_key_derivation_key_agreement()`
input function, which calculates a shared secret for the key derivation
function.
Where an application needs direct access to the shared secret, it can call
`psa_raw_key_agreement()` instead. Note that in general the shared secret is not
directly suitable for use as a key because it is biased.
Randomness and key generation
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
We strongly recommended that implementations include a random generator,
consisting of a cryptographically secure pseudo-random generator (CSPRNG), which
is adequately seeded with a cryptographic-quality hardware entropy source,
commonly referred to as a true random number generator (TRNG). Constrained
implementations can omit the random generation functionality if they do not
implement any algorithm that requires randomness internally, and they do not
provide a key generation functionality. For example, a special-purpose component
for signature verification can omit this.
It is recommended that applications use `psa_generate_key()`,
`psa_cipher_generate_iv()` or `psa_aead_generate_nonce()` to generate
suitably-formatted random data, as applicable. In addition, the API includes a
function `psa_generate_random()` to generate and extract arbitrary random data.