Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for interruptible signature calculation and verification #107

Open
wants to merge 12 commits into
base: main
Choose a base branch
from
Open
40 changes: 40 additions & 0 deletions doc/crypto/api.db/psa/crypto.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ typedef uint32_t psa_pake_primitive_t;
typedef uint8_t psa_pake_primitive_type_t;
typedef uint8_t psa_pake_role_t;
typedef uint8_t psa_pake_step_t;
typedef /* implementation-defined type */ psa_sign_iop_t;
typedef /* implementation-defined type */ psa_verify_iop_t;
#define PSA_AEAD_DECRYPT_OUTPUT_MAX_SIZE(ciphertext_length) \
/* implementation-defined value */
#define PSA_AEAD_DECRYPT_OUTPUT_SIZE(key_type, alg, ciphertext_length) \
Expand Down Expand Up @@ -237,6 +239,7 @@ typedef uint8_t psa_pake_step_t;
/* specification-defined value */
#define PSA_HASH_SUSPEND_OUTPUT_MAX_SIZE /* implementation-defined value */
#define PSA_HASH_SUSPEND_OUTPUT_SIZE(alg) /* specification-defined value */
#define PSA_IOP_MAX_OPS_UNLIMITED UINT32_MAX
#define PSA_KEY_ATTRIBUTES_INIT /* implementation-defined value */
#define PSA_KEY_DERIVATION_INPUT_CONTEXT /* implementation-defined value */
#define PSA_KEY_DERIVATION_INPUT_COST /* implementation-defined value */
Expand Down Expand Up @@ -367,10 +370,12 @@ typedef uint8_t psa_pake_step_t;
#define PSA_RAW_KEY_AGREEMENT_OUTPUT_SIZE(key_type, key_bits) \
/* implementation-defined value */
#define PSA_SIGNATURE_MAX_SIZE /* implementation-defined value */
#define PSA_SIGN_IOP_INIT /* implementation-defined value */
#define PSA_SIGN_OUTPUT_SIZE(key_type, key_bits, alg) \
/* implementation-defined value */
#define PSA_TLS12_ECJPAKE_TO_PMS_OUTPUT_SIZE 32
#define PSA_TLS12_PSK_TO_MS_PSK_MAX_SIZE /* implementation-defined value */
#define PSA_VERIFY_IOP_INIT /* implementation-defined value */
psa_status_t psa_aead_abort(psa_aead_operation_t * operation);
psa_status_t psa_aead_decrypt(psa_key_id_t key,
psa_algorithm_t alg,
Expand Down Expand Up @@ -553,6 +558,8 @@ psa_status_t psa_import_key(const psa_key_attributes_t * attributes,
const uint8_t * data,
size_t data_length,
psa_key_id_t * key);
uint32_t psa_iop_get_max_ops(void);
void psa_iop_set_max_ops(uint32_t max_ops);
psa_status_t psa_key_agreement(psa_key_id_t private_key,
const uint8_t * peer_key,
size_t peer_key_length,
Expand Down Expand Up @@ -691,6 +698,23 @@ psa_status_t psa_sign_hash(psa_key_id_t key,
uint8_t * signature,
size_t signature_size,
size_t * signature_length);
psa_status_t psa_sign_iop_abort(psa_sign_iop_t * operation);
psa_status_t psa_sign_iop_complete(psa_sign_iop_t * operation,
uint8_t * signature,
size_t signature_size,
size_t * signature_length);
uint32_t psa_sign_iop_get_num_ops(psa_sign_iop_t * operation);
psa_status_t psa_sign_iop_hash(psa_sign_iop_t * operation,
const uint8_t * hash,
size_t hash_length);
psa_sign_iop_t psa_sign_iop_init(void);
psa_status_t psa_sign_iop_setup(psa_sign_iop_t * operation,
psa_key_id_t key,
psa_algorithm_t alg);
psa_status_t psa_sign_iop_setup_complete(psa_sign_iop_t * operation);
psa_status_t psa_sign_iop_update(psa_sign_iop_t * operation,
const uint8_t * input,
size_t input_length);
psa_status_t psa_sign_message(psa_key_id_t key,
psa_algorithm_t alg,
const uint8_t * input,
Expand All @@ -704,6 +728,22 @@ psa_status_t psa_verify_hash(psa_key_id_t key,
size_t hash_length,
const uint8_t * signature,
size_t signature_length);
psa_status_t psa_verify_iop_abort(psa_verify_iop_t * operation);
psa_status_t psa_verify_iop_complete(psa_verify_iop_t * operation);
uint32_t psa_verify_iop_get_num_ops(psa_verify_iop_t * operation);
psa_status_t psa_verify_iop_hash(psa_verify_iop_t * operation,
const uint8_t * hash,
size_t hash_length);
psa_verify_iop_t psa_verify_iop_init(void);
psa_status_t psa_verify_iop_setup(psa_verify_iop_t * operation,
psa_key_id_t key,
psa_algorithm_t alg,
const uint8_t * signature,
size_t signature_length);
psa_status_t psa_verify_iop_setup_complete(psa_verify_iop_t * operation);
psa_status_t psa_verify_iop_update(psa_verify_iop_t * operation,
const uint8_t * input,
size_t input_length);
psa_status_t psa_verify_message(psa_key_id_t key,
psa_algorithm_t alg,
const uint8_t * input,
Expand Down
12 changes: 10 additions & 2 deletions doc/crypto/api/keys/policy.rst
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ The usage flags are encoded in a bitmask, which has the type `psa_key_usage_t`.
* `psa_mac_compute()`
* `psa_mac_sign_setup()`
* `psa_sign_message()`
* `psa_sign_iop_setup()`, when signing a message.

For a key pair, this concerns the private key.

Expand All @@ -195,6 +196,7 @@ The usage flags are encoded in a bitmask, which has the type `psa_key_usage_t`.
* `psa_mac_verify()`
* `psa_mac_verify_setup()`
* `psa_verify_message()`
* `psa_verify_iop_setup()`, when verifying the signature of a message.

For a key pair, this concerns the public key.

Expand All @@ -204,7 +206,10 @@ The usage flags are encoded in a bitmask, which has the type `psa_key_usage_t`.
.. summary::
Permission to sign a message hash with the key.

This flag is required to use the key to sign a message hash in an asymmetric signature operation. The flag must be present on keys used when calling `psa_sign_hash()`.
This flag is required to use the key to sign a pre-computed message hash in an asymmetric signature operation. The flag must be present on keys used with the following APIs:

* `psa_sign_hash()`
* `psa_sign_iop_setup()` when signing a pre-computed hash.

This flag automatically sets `PSA_KEY_USAGE_SIGN_MESSAGE`: if an application sets the flag `PSA_KEY_USAGE_SIGN_HASH` when creating a key, then the key always has the permissions conveyed by `PSA_KEY_USAGE_SIGN_MESSAGE`, and the flag `PSA_KEY_USAGE_SIGN_MESSAGE` will also be present when the application queries the usage flags of the key.

Expand All @@ -216,7 +221,10 @@ The usage flags are encoded in a bitmask, which has the type `psa_key_usage_t`.
.. summary::
Permission to verify a message hash with the key.

This flag is required to use the key to verify a message hash in an asymmetric signature verification operation. The flag must be present on keys used when calling `psa_verify_hash()`.
This flag is required to use the key to verify a pre-computed message hash in an asymmetric signature verification operation. The flag must be present on keys used with the following APIs:

* `psa_verify_hash()`
* `psa_verify_iop_setup()`, when verifying the signature of a pre-computed hash.

This flag automatically sets `PSA_KEY_USAGE_VERIFY_MESSAGE`: if an application sets the flag `PSA_KEY_USAGE_VERIFY_HASH` when creating a key, then the key always has the permissions conveyed by `PSA_KEY_USAGE_VERIFY_MESSAGE`, and the flag `PSA_KEY_USAGE_VERIFY_MESSAGE` will also be present when the application queries the usage flags of the key.

Expand Down
52 changes: 52 additions & 0 deletions doc/crypto/api/library/library.rst
Original file line number Diff line number Diff line change
Expand Up @@ -73,3 +73,55 @@ Library initialization

.. 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.


Interruptible operation limit
-----------------------------

Using an interruptible operation, an application can perform an expensive cryptographic computation while limiting the execution time of each function call. The execution limit is controlled via the *maximum ops* value.

See :secref:`interruptible-operations`.

.. function:: psa_iop_set_max_ops

.. summary::
Set the maximum number of *ops* allowed to be executed by an interruptible function in a single call.

.. param:: uint32_t max_ops
The maximum number of ops to be executed in a single call, this can be a number from ``0`` to `PSA_IOP_MAX_OPS_UNLIMITED`, where ``0`` is obviously the least amount of work done per call.

.. return:: void

Interruptible functions use this value to limit the computation that is done in any single call to the function. If this limit is reached, the function will return :code:`PSA_OPERATION_INCOMPLETE`, and the caller must repeat the function call until a different status code is returned, or abort the operation.

After initialization of the implementation, the maximum *ops* defaults to `PSA_IOP_MAX_OPS_UNLIMITED`. This means that the whole operation will complete in a single call, regardless of the number of *ops* required. An application must call `psa_iop_set_max_ops()` to set a different limit.

.. note::

The time taken to execute a single *op* is implementation specific and depends on software, hardware, the algorithm, key type and curve chosen. Even within a single operation, successive ops can take differing amounts of time. The only guarantee is that lower values for ``max_ops`` means functions will block for a lesser maximum amount of time and conversely larger values will mean blocking for a larger maximum amount of time. The functions `psa_sign_iop_get_num_ops()` and `psa_verify_iop_get_num_ops()` are provided to help with tuning this value.

.. admonition:: Implementation note

The interpretation of this maximum number is obviously also implementation defined. On a hard real-time system, this can indicate a hard deadline, which is good, as a real-time system needs a guarantee of not spending more than X time, however care must be taken to avoid the situation whereby calls just return, not being able to do any actual work within the allotted time. On a non-real-time system, the implementation can be more relaxed, but again whether this number should be interpreted as as hard or soft limit or even whether a less than or equals as regards to ops executed in a single call is implementation defined.

.. warning::
With implementations that interpret this number as a hard limit, setting this number too small can result in an infinite loop, whereby each call results in immediate return with no computation done.

.. function:: psa_iop_get_max_ops

.. summary::
Get the maximum number of *ops* allowed to be executed by an interruptible function in a single call.

.. return:: uint32_t
Maximum number of *ops* allowed to be executed by an interruptible function in a single call.

This returns the value last set in a call to `psa_iop_set_max_ops()`.

.. macro:: PSA_IOP_MAX_OPS_UNLIMITED
:definition: UINT32_MAX

.. summary::

Maximum value for use with `psa_iop_set_max_ops()`.

Using this value in a call to `psa_iop_set_max_ops()` will cause interruptible functions to complete their calculation before returning.
50 changes: 26 additions & 24 deletions doc/crypto/api/library/status.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,29 +12,31 @@ The following elements are defined in :file:`psa/error.h` from :cite-title:`PSA-

.. code-block:: xref

typedef int32_t psa_status_t;

#define PSA_SUCCESS ((psa_status_t)0)

#define PSA_ERROR_GENERIC_ERROR ((psa_status_t)-132)
#define PSA_ERROR_NOT_PERMITTED ((psa_status_t)-133)
#define PSA_ERROR_NOT_SUPPORTED ((psa_status_t)-134)
#define PSA_ERROR_INVALID_ARGUMENT ((psa_status_t)-135)
#define PSA_ERROR_INVALID_HANDLE ((psa_status_t)-136)
#define PSA_ERROR_BAD_STATE ((psa_status_t)-137)
#define PSA_ERROR_BUFFER_TOO_SMALL ((psa_status_t)-138)
#define PSA_ERROR_ALREADY_EXISTS ((psa_status_t)-139)
#define PSA_ERROR_DOES_NOT_EXIST ((psa_status_t)-140)
#define PSA_ERROR_INSUFFICIENT_MEMORY ((psa_status_t)-141)
#define PSA_ERROR_INSUFFICIENT_STORAGE ((psa_status_t)-142)
#define PSA_ERROR_INSUFFICIENT_DATA ((psa_status_t)-143)
#define PSA_ERROR_COMMUNICATION_FAILURE ((psa_status_t)-145)
#define PSA_ERROR_STORAGE_FAILURE ((psa_status_t)-146)
#define PSA_ERROR_HARDWARE_FAILURE ((psa_status_t)-147)
#define PSA_ERROR_INVALID_SIGNATURE ((psa_status_t)-149)
#define PSA_ERROR_CORRUPTION_DETECTED ((psa_status_t)-151)
#define PSA_ERROR_DATA_CORRUPT ((psa_status_t)-152)
#define PSA_ERROR_DATA_INVALID ((psa_status_t)-153)
typedef int32_t psa_status_t;

#define PSA_SUCCESS ((psa_status_t)0)

#define PSA_ERROR_GENERIC_ERROR ((psa_status_t)-132)
#define PSA_ERROR_NOT_PERMITTED ((psa_status_t)-133)
#define PSA_ERROR_NOT_SUPPORTED ((psa_status_t)-134)
#define PSA_ERROR_INVALID_ARGUMENT ((psa_status_t)-135)
#define PSA_ERROR_INVALID_HANDLE ((psa_status_t)-136)
#define PSA_ERROR_BAD_STATE ((psa_status_t)-137)
#define PSA_ERROR_BUFFER_TOO_SMALL ((psa_status_t)-138)
#define PSA_ERROR_ALREADY_EXISTS ((psa_status_t)-139)
#define PSA_ERROR_DOES_NOT_EXIST ((psa_status_t)-140)
#define PSA_ERROR_INSUFFICIENT_MEMORY ((psa_status_t)-141)
#define PSA_ERROR_INSUFFICIENT_STORAGE ((psa_status_t)-142)
#define PSA_ERROR_INSUFFICIENT_DATA ((psa_status_t)-143)
#define PSA_ERROR_COMMUNICATION_FAILURE ((psa_status_t)-145)
#define PSA_ERROR_STORAGE_FAILURE ((psa_status_t)-146)
#define PSA_ERROR_HARDWARE_FAILURE ((psa_status_t)-147)
#define PSA_ERROR_INVALID_SIGNATURE ((psa_status_t)-149)
#define PSA_ERROR_CORRUPTION_DETECTED ((psa_status_t)-151)
#define PSA_ERROR_DATA_CORRUPT ((psa_status_t)-152)
#define PSA_ERROR_DATA_INVALID ((psa_status_t)-153)

#define PSA_OPERATION_INCOMPLETE ((psa_status_t)-248)

These definitions must be available to an application that includes the :file:`psa/crypto.h` header file.

Expand Down Expand Up @@ -79,7 +81,7 @@ Some of the common status codes have a more precise meaning when returned by a f
.. _specific-errors:

Error codes specific to the |API|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

.. header:: psa/crypto
:seq: 2
Expand Down
Loading