diff --git a/ChangeLog.d/add_interruptible_sign_hash b/ChangeLog.d/add_interruptible_sign_hash
new file mode 100644
index 000000000..3d933038e
--- /dev/null
+++ b/ChangeLog.d/add_interruptible_sign_hash
@@ -0,0 +1,5 @@
+Features
+ * Add an interruptible version of sign and verify hash to the PSA interface,
+ backed by internal library support for ECDSA signing and verification.
+
+
diff --git a/include/mbedtls/ecdsa.h b/include/mbedtls/ecdsa.h
index 9847a6836..c5d9701f6 100644
--- a/include/mbedtls/ecdsa.h
+++ b/include/mbedtls/ecdsa.h
@@ -222,6 +222,134 @@ int mbedtls_ecdsa_sign_det_ext(mbedtls_ecp_group *grp, mbedtls_mpi *r,
void *p_rng_blind);
#endif /* MBEDTLS_ECDSA_DETERMINISTIC */
+#if !defined(MBEDTLS_ECDSA_SIGN_ALT)
+/**
+ * \brief This function computes the ECDSA signature of a
+ * previously-hashed message, in a restartable way.
+ *
+ * \note The deterministic version implemented in
+ * mbedtls_ecdsa_sign_det_restartable() is usually
+ * preferred.
+ *
+ * \note This function is like \c mbedtls_ecdsa_sign() but
+ * it can return early and restart according to the
+ * limit set with \c mbedtls_ecp_set_max_ops() to
+ * reduce blocking.
+ *
+ * \note If the bitlength of the message hash is larger
+ * than the bitlength of the group order, then the
+ * hash is truncated as defined in Standards for
+ * Efficient Cryptography Group (SECG): SEC1 Elliptic
+ * Curve Cryptography, section 4.1.3, step 5.
+ *
+ * \see ecp.h
+ *
+ * \param grp The context for the elliptic curve to use.
+ * This must be initialized and have group parameters
+ * set, for example through mbedtls_ecp_group_load().
+ * \param r The MPI context in which to store the first part
+ * the signature. This must be initialized.
+ * \param s The MPI context in which to store the second part
+ * the signature. This must be initialized.
+ * \param d The private signing key. This must be initialized
+ * and setup, for example through
+ * mbedtls_ecp_gen_privkey().
+ * \param buf The hashed content to be signed. This must be a readable
+ * buffer of length \p blen Bytes. It may be \c NULL if
+ * \p blen is zero.
+ * \param blen The length of \p buf in Bytes.
+ * \param f_rng The RNG function. This must not be \c NULL.
+ * \param p_rng The RNG context to be passed to \p f_rng. This may be
+ * \c NULL if \p f_rng doesn't need a context parameter.
+ * \param f_rng_blind The RNG function used for blinding. This must not be
+ * \c NULL.
+ * \param p_rng_blind The RNG context to be passed to \p f_rng. This may be
+ * \c NULL if \p f_rng doesn't need a context parameter.
+ * \param rs_ctx The restart context to use. This may be \c NULL
+ * to disable restarting. If it is not \c NULL, it
+ * must point to an initialized restart context.
+ *
+ * \return \c 0 on success.
+ * \return #MBEDTLS_ERR_ECP_IN_PROGRESS if maximum number of
+ * operations was reached: see \c
+ * mbedtls_ecp_set_max_ops().
+ * \return Another \c MBEDTLS_ERR_ECP_XXX, \c
+ * MBEDTLS_ERR_MPI_XXX or \c MBEDTLS_ERR_ASN1_XXX
+ * error code on failure.
+ */
+int mbedtls_ecdsa_sign_restartable(
+ mbedtls_ecp_group *grp,
+ mbedtls_mpi *r, mbedtls_mpi *s,
+ const mbedtls_mpi *d,
+ const unsigned char *buf, size_t blen,
+ int (*f_rng)(void *, unsigned char *, size_t),
+ void *p_rng,
+ int (*f_rng_blind)(void *, unsigned char *, size_t),
+ void *p_rng_blind,
+ mbedtls_ecdsa_restart_ctx *rs_ctx);
+
+#if defined(MBEDTLS_ECDSA_DETERMINISTIC)
+
+/**
+ * \brief This function computes the ECDSA signature of a
+ * previously-hashed message, in a restartable way.
+ *
+ * \note This function is like \c
+ * mbedtls_ecdsa_sign_det_ext() but it can return
+ * early and restart according to the limit set with
+ * \c mbedtls_ecp_set_max_ops() to reduce blocking.
+ *
+ * \note If the bitlength of the message hash is larger
+ * than the bitlength of the group order, then the
+ * hash is truncated as defined in Standards for
+ * Efficient Cryptography Group (SECG): SEC1 Elliptic
+ * Curve Cryptography, section 4.1.3, step 5.
+ *
+ * \see ecp.h
+ *
+ * \param grp The context for the elliptic curve to use.
+ * This must be initialized and have group parameters
+ * set, for example through mbedtls_ecp_group_load().
+ * \param r The MPI context in which to store the first part
+ * the signature. This must be initialized.
+ * \param s The MPI context in which to store the second part
+ * the signature. This must be initialized.
+ * \param d The private signing key. This must be initialized
+ * and setup, for example through
+ * mbedtls_ecp_gen_privkey().
+ * \param buf The hashed content to be signed. This must be a readable
+ * buffer of length \p blen Bytes. It may be \c NULL if
+ * \p blen is zero.
+ * \param blen The length of \p buf in Bytes.
+ * \param f_rng_blind The RNG function used for blinding. This must not be
+ * \c NULL.
+ * \param p_rng_blind The RNG context to be passed to \p f_rng. This may be
+ * \c NULL if \p f_rng doesn't need a context parameter.
+ * \param rs_ctx The restart context to use. This may be \c NULL
+ * to disable restarting. If it is not \c NULL, it
+ * must point to an initialized restart context.
+ *
+ * \return \c 0 on success.
+ * \return #MBEDTLS_ERR_ECP_IN_PROGRESS if maximum number of
+ * operations was reached: see \c
+ * mbedtls_ecp_set_max_ops().
+ * \return Another \c MBEDTLS_ERR_ECP_XXX, \c
+ * MBEDTLS_ERR_MPI_XXX or \c MBEDTLS_ERR_ASN1_XXX
+ * error code on failure.
+ */
+int mbedtls_ecdsa_sign_det_restartable(
+ mbedtls_ecp_group *grp,
+ mbedtls_mpi *r, mbedtls_mpi *s,
+ const mbedtls_mpi *d, const unsigned char *buf, size_t blen,
+ mbedtls_md_type_t md_alg,
+ int (*f_rng_blind)(void *, unsigned char *, size_t),
+ void *p_rng_blind,
+ mbedtls_ecdsa_restart_ctx *rs_ctx);
+
+#endif /* MBEDTLS_ECDSA_DETERMINISTIC */
+
+#endif /* !MBEDTLS_ECDSA_SIGN_ALT */
+
/**
* \brief This function verifies the ECDSA signature of a
* previously-hashed message.
@@ -257,6 +385,51 @@ int mbedtls_ecdsa_verify(mbedtls_ecp_group *grp,
const mbedtls_ecp_point *Q, const mbedtls_mpi *r,
const mbedtls_mpi *s);
+#if !defined(MBEDTLS_ECDSA_VERIFY_ALT)
+/**
+ * \brief This function verifies the ECDSA signature of a
+ * previously-hashed message, in a restartable manner
+ *
+ * \note If the bitlength of the message hash is larger than the
+ * bitlength of the group order, then the hash is truncated as
+ * defined in Standards for Efficient Cryptography Group
+ * (SECG): SEC1 Elliptic Curve Cryptography, section
+ * 4.1.4, step 3.
+ *
+ * \see ecp.h
+ *
+ * \param grp The ECP group to use.
+ * This must be initialized and have group parameters
+ * set, for example through mbedtls_ecp_group_load().
+ * \param buf The hashed content that was signed. This must be a readable
+ * buffer of length \p blen Bytes. It may be \c NULL if
+ * \p blen is zero.
+ * \param blen The length of \p buf in Bytes.
+ * \param Q The public key to use for verification. This must be
+ * initialized and setup.
+ * \param r The first integer of the signature.
+ * This must be initialized.
+ * \param s The second integer of the signature.
+ * This must be initialized.
+ * \param rs_ctx The restart context to use. This may be \c NULL to disable
+ * restarting. If it is not \c NULL, it must point to an
+ * initialized restart context.
+ *
+ * \return \c 0 on success.
+ * \return #MBEDTLS_ERR_ECP_IN_PROGRESS if maximum number of
+ * operations was reached: see \c mbedtls_ecp_set_max_ops().
+ * \return An \c MBEDTLS_ERR_ECP_XXX or \c MBEDTLS_MPI_XXX
+ * error code on failure.
+ */
+int mbedtls_ecdsa_verify_restartable(mbedtls_ecp_group *grp,
+ const unsigned char *buf, size_t blen,
+ const mbedtls_ecp_point *Q,
+ const mbedtls_mpi *r,
+ const mbedtls_mpi *s,
+ mbedtls_ecdsa_restart_ctx *rs_ctx);
+
+#endif /* !MBEDTLS_ECDSA_VERIFY_ALT */
+
/**
* \brief This function computes the ECDSA signature and writes it
* to a buffer, serialized as defined in RFC-4492:
diff --git a/include/mbedtls/ecp.h b/include/mbedtls/ecp.h
index 7a28a1957..1590ef21e 100644
--- a/include/mbedtls/ecp.h
+++ b/include/mbedtls/ecp.h
@@ -472,6 +472,12 @@ mbedtls_ecp_keypair;
* only enabled for specific sides and key exchanges
* (currently only for clients and ECDHE-ECDSA).
*
+ * \warning Using the PSA interruptible interfaces with keys in local
+ * storage and no accelerator driver will also call this
+ * function to set the values specified via those interfaces,
+ * overwriting values previously set. Care should be taken if
+ * mixing these two interfaces.
+ *
* \param max_ops Maximum number of basic operations done in a row.
* Default: 0 (unlimited).
* Lower (non-zero) values mean ECC functions will block for
diff --git a/include/psa/crypto.h b/include/psa/crypto.h
index 2b9b2a27e..80bf5c969 100644
--- a/include/psa/crypto.h
+++ b/include/psa/crypto.h
@@ -4045,6 +4045,628 @@ psa_status_t psa_generate_key(const psa_key_attributes_t *attributes,
/**@}*/
+/** \defgroup interruptible_hash Interruptible sign/verify hash
+ * @{
+ */
+
+/** The type of the state data structure for interruptible hash
+ * signing operations.
+ *
+ * Before calling any function on a sign hash operation object, the
+ * application must initialize it by any of the following means:
+ * - Set the structure to all-bits-zero, for example:
+ * \code
+ * psa_sign_hash_interruptible_operation_t operation;
+ * memset(&operation, 0, sizeof(operation));
+ * \endcode
+ * - Initialize the structure to logical zero values, for example:
+ * \code
+ * psa_sign_hash_interruptible_operation_t operation = {0};
+ * \endcode
+ * - Initialize the structure to the initializer
+ * #PSA_SIGN_HASH_INTERRUPTIBLE_OPERATION_INIT, for example:
+ * \code
+ * psa_sign_hash_interruptible_operation_t operation =
+ * PSA_SIGN_HASH_INTERRUPTIBLE_OPERATION_INIT;
+ * \endcode
+ * - Assign the result of the function
+ * psa_sign_hash_interruptible_operation_init() to the structure, for
+ * example:
+ * \code
+ * psa_sign_hash_interruptible_operation_t operation;
+ * operation = psa_sign_hash_interruptible_operation_init();
+ * \endcode
+ *
+ * This is an implementation-defined \c struct. Applications should not
+ * make any assumptions about the content of this structure.
+ * Implementation details can change in future versions without notice. */
+typedef struct psa_sign_hash_interruptible_operation_s psa_sign_hash_interruptible_operation_t;
+
+/** The type of the state data structure for interruptible hash
+ * verification operations.
+ *
+ * Before calling any function on a sign hash operation object, the
+ * application must initialize it by any of the following means:
+ * - Set the structure to all-bits-zero, for example:
+ * \code
+ * psa_verify_hash_interruptible_operation_t operation;
+ * memset(&operation, 0, sizeof(operation));
+ * \endcode
+ * - Initialize the structure to logical zero values, for example:
+ * \code
+ * psa_verify_hash_interruptible_operation_t operation = {0};
+ * \endcode
+ * - Initialize the structure to the initializer
+ * #PSA_VERIFY_HASH_INTERRUPTIBLE_OPERATION_INIT, for example:
+ * \code
+ * psa_verify_hash_interruptible_operation_t operation =
+ * PSA_VERIFY_HASH_INTERRUPTIBLE_OPERATION_INIT;
+ * \endcode
+ * - Assign the result of the function
+ * psa_verify_hash_interruptible_operation_init() to the structure, for
+ * example:
+ * \code
+ * psa_verify_hash_interruptible_operation_t operation;
+ * operation = psa_verify_hash_interruptible_operation_init();
+ * \endcode
+ *
+ * This is an implementation-defined \c struct. Applications should not
+ * make any assumptions about the content of this structure.
+ * Implementation details can change in future versions without notice. */
+typedef struct psa_verify_hash_interruptible_operation_s psa_verify_hash_interruptible_operation_t;
+
+/**
+ * \brief Set the maximum number of ops allowed to be
+ * executed by an interruptible function in a
+ * single call.
+ *
+ * \warning This is a beta API, and thus subject to change
+ * at any point. It is not bound by the usual
+ * interface stability promises.
+ *
+ * \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 \p max_ops means functions will block for a
+ * lesser maximum amount of time. The functions
+ * \c psa_sign_interruptible_get_num_ops() and
+ * \c psa_verify_interruptible_get_num_ops() are
+ * provided to help with tuning this value.
+ *
+ * \note This value defaults to
+ * #PSA_INTERRUPTIBLE_MAX_OPS_UNLIMITED, which
+ * means the whole operation will be done in one
+ * go, regardless of the number of ops required.
+ *
+ * \note If more ops are needed to complete a
+ * computation, #PSA_OPERATION_INCOMPLETE will be
+ * returned by the function performing the
+ * computation. It is then the caller's
+ * responsibility to either call again with the
+ * same operation context until it returns 0 or an
+ * error code; or to call the relevant abort
+ * function if the answer is no longer required.
+ *
+ * \note The interpretation of \p max_ops is also
+ * implementation defined. On a hard real time
+ * system, this can indicate a hard deadline, as a
+ * real-time system needs a guarantee of not
+ * spending more than X time, however care must be
+ * taken in such an implementation 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.
+ *
+ * \note For keys in local storage when no accelerator
+ * driver applies, please see also the
+ * documentation for \c mbedtls_ecp_set_max_ops(),
+ * which is the internal implementation in these
+ * cases.
+ *
+ * \warning With implementations that interpret this number
+ * as a hard limit, setting this number too small
+ * may result in an infinite loop, whereby each
+ * call results in immediate return with no ops
+ * done (as there is not enough time to execute
+ * any), and thus no result will ever be achieved.
+ *
+ * \note This only applies to functions whose
+ * documentation mentions they may return
+ * #PSA_OPERATION_INCOMPLETE.
+ *
+ * \param max_ops The maximum number of ops to be executed in a
+ * single call. This can be a number from 0 to
+ * #PSA_INTERRUPTIBLE_MAX_OPS_UNLIMITED, where 0
+ * is the least amount of work done per call.
+ */
+void psa_interruptible_set_max_ops(uint32_t max_ops);
+
+/**
+ * \brief Get the maximum number of ops allowed to be
+ * executed by an interruptible function in a
+ * single call. This will return the last
+ * value set by
+ * \c psa_interruptible_set_max_ops() or
+ * #PSA_INTERRUPTIBLE_MAX_OPS_UNLIMITED if
+ * that function has never been called.
+ *
+ * \warning This is a beta API, and thus subject to change
+ * at any point. It is not bound by the usual
+ * interface stability promises.
+ *
+ * \return Maximum number of ops allowed to be
+ * executed by an interruptible function in a
+ * single call.
+ */
+uint32_t psa_interruptible_get_max_ops(void);
+
+/**
+ * \brief Get the number of ops that a hash signing
+ * operation has taken so far. If the operation
+ * has completed, then this will represent the
+ * number of ops required for the entire
+ * operation. After initialization or calling
+ * \c psa_sign_hash_interruptible_abort() on
+ * the operation, a value of 0 will be returned.
+ *
+ * \warning This is a beta API, and thus subject to change
+ * at any point. It is not bound by the usual
+ * interface stability promises.
+ *
+ * This is a helper provided to help you tune the
+ * value passed to \c
+ * psa_interruptible_set_max_ops().
+ *
+ * \param operation The \c psa_sign_hash_interruptible_operation_t
+ * to use. This must be initialized first.
+ *
+ * \return Number of ops that the operation has taken so
+ * far.
+ */
+uint32_t psa_sign_hash_get_num_ops(
+ const psa_sign_hash_interruptible_operation_t *operation);
+
+/**
+ * \brief Get the number of ops that a hash verification
+ * operation has taken so far. If the operation
+ * has completed, then this will represent the
+ * number of ops required for the entire
+ * operation. After initialization or calling \c
+ * psa_verify_hash_interruptible_abort() on the
+ * operation, a value of 0 will be returned.
+ *
+ * \warning This is a beta API, and thus subject to change
+ * at any point. It is not bound by the usual
+ * interface stability promises.
+ *
+ * This is a helper provided to help you tune the
+ * value passed to \c
+ * psa_interruptible_set_max_ops().
+ *
+ * \param operation The \c
+ * psa_verify_hash_interruptible_operation_t to
+ * use. This must be initialized first.
+ *
+ * \return Number of ops that the operation has taken so
+ * far.
+ */
+uint32_t psa_verify_hash_get_num_ops(
+ const psa_verify_hash_interruptible_operation_t *operation);
+
+/**
+ * \brief Start signing a hash or short message with a
+ * private key, in an interruptible manner.
+ *
+ * \see \c psa_sign_hash_complete()
+ *
+ * \warning This is a beta API, and thus subject to change
+ * at any point. It is not bound by the usual
+ * interface stability promises.
+ *
+ * \note This function combined with \c
+ * psa_sign_hash_complete() is equivalent to
+ * \c psa_sign_hash() but
+ * \c psa_sign_hash_complete() can return early and
+ * resume according to the limit set with \c
+ * psa_interruptible_set_max_ops() to reduce the
+ * maximum time spent in a function call.
+ *
+ * \note Users should call \c psa_sign_hash_complete()
+ * repeatedly on the same context after a
+ * successful call to this function until \c
+ * psa_sign_hash_complete() either returns 0 or an
+ * error. \c psa_sign_hash_complete() will return
+ * #PSA_OPERATION_INCOMPLETE if there is more work
+ * to do. Alternatively users can call
+ * \c psa_sign_hash_abort() at any point if they no
+ * longer want the result.
+ *
+ * \note If this function returns an error status, the
+ * operation enters an error state and must be
+ * aborted by calling \c psa_sign_hash_abort().
+ *
+ * \param[in, out] operation The \c psa_sign_hash_interruptible_operation_t
+ * to use. This must be initialized first.
+ *
+ * \param key Identifier of the key to use for the operation.
+ * It must be an asymmetric key pair. The key must
+ * allow the usage #PSA_KEY_USAGE_SIGN_HASH.
+ * \param alg A signature algorithm (\c PSA_ALG_XXX
+ * value such that #PSA_ALG_IS_SIGN_HASH(\p alg)
+ * is true), that is compatible with
+ * the type of \p key.
+ * \param[in] hash The hash or message to sign.
+ * \param hash_length Size of the \p hash buffer in bytes.
+ *
+ * \retval #PSA_SUCCESS
+ * The operation started successfully - call \c psa_sign_hash_complete()
+ * with the same context to complete the operation
+ *
+ * \retval #PSA_ERROR_INVALID_HANDLE
+ * \retval #PSA_ERROR_NOT_PERMITTED
+ * The key does not have the #PSA_KEY_USAGE_SIGN_HASH flag, or it does
+ * not permit the requested algorithm.
+ * \retval #PSA_ERROR_BAD_STATE
+ * An operation has previously been started on this context, and is
+ * still in progress.
+ * \retval #PSA_ERROR_NOT_SUPPORTED
+ * \retval #PSA_ERROR_INVALID_ARGUMENT
+ * \retval #PSA_ERROR_INSUFFICIENT_MEMORY
+ * \retval #PSA_ERROR_COMMUNICATION_FAILURE
+ * \retval #PSA_ERROR_HARDWARE_FAILURE
+ * \retval #PSA_ERROR_CORRUPTION_DETECTED
+ * \retval #PSA_ERROR_STORAGE_FAILURE
+ * \retval #PSA_ERROR_DATA_CORRUPT
+ * \retval #PSA_ERROR_DATA_INVALID
+ * \retval #PSA_ERROR_INSUFFICIENT_ENTROPY
+ * \retval #PSA_ERROR_BAD_STATE
+ * The library has not been previously initialized by psa_crypto_init().
+ * It is implementation-dependent whether a failure to initialize
+ * results in this error code.
+ */
+psa_status_t psa_sign_hash_start(
+ psa_sign_hash_interruptible_operation_t *operation,
+ mbedtls_svc_key_id_t key, psa_algorithm_t alg,
+ const uint8_t *hash, size_t hash_length);
+
+/**
+ * \brief Continue and eventually complete the action of
+ * signing a hash or short message with a private
+ * key, in an interruptible manner.
+ *
+ * \see \c psa_sign_hash_start()
+ *
+ * \warning This is a beta API, and thus subject to change
+ * at any point. It is not bound by the usual
+ * interface stability promises.
+ *
+ * \note This function combined with \c
+ * psa_sign_hash_start() is equivalent to
+ * \c psa_sign_hash() but this function can return
+ * early and resume according to the limit set with
+ * \c psa_interruptible_set_max_ops() to reduce the
+ * maximum time spent in a function call.
+ *
+ * \note Users should call this function on the same
+ * operation object repeatedly until it either
+ * returns 0 or an error. This function will return
+ * #PSA_OPERATION_INCOMPLETE if there is more work
+ * to do. Alternatively users can call
+ * \c psa_sign_hash_abort() at any point if they no
+ * longer want the result.
+ *
+ * \note When this function returns successfully, the
+ * operation becomes inactive. If this function
+ * returns an error status, the operation enters an
+ * error state and must be aborted by calling
+ * \c psa_sign_hash_abort().
+ *
+ * \param[in, out] operation The \c psa_sign_hash_interruptible_operation_t
+ * to use. This must be initialized first, and have
+ * had \c psa_sign_hash_start() called with it
+ * first.
+ *
+ * \param[out] signature Buffer where the signature is to be written.
+ * \param signature_size Size of the \p signature buffer in bytes. This
+ * must be appropriate for the selected
+ * algorithm and key:
+ * - The required signature size is
+ * #PSA_SIGN_OUTPUT_SIZE(\c key_type, \c
+ * key_bits, \c alg) where \c key_type and \c
+ * key_bits are the type and bit-size
+ * respectively of key.
+ * - #PSA_SIGNATURE_MAX_SIZE evaluates to the
+ * maximum signature size of any supported
+ * signature algorithm.
+ * \param[out] signature_length On success, the number of bytes that make up
+ * the returned signature value.
+ *
+ * \retval #PSA_SUCCESS
+ * Operation completed successfully
+ *
+ * \retval #PSA_OPERATION_INCOMPLETE
+ * Operation was interrupted due to the setting of \c
+ * psa_interruptible_set_max_ops(). There is still work to be done.
+ * Call this function again with the same operation object.
+ *
+ * \retval #PSA_ERROR_BUFFER_TOO_SMALL
+ * The size of the \p signature buffer is too small. You can
+ * determine a sufficient buffer size by calling
+ * #PSA_SIGN_OUTPUT_SIZE(\c key_type, \c key_bits, \p alg)
+ * where \c key_type and \c key_bits are the type and bit-size
+ * respectively of \p key.
+ *
+ * \retval #PSA_ERROR_BAD_STATE
+ * An operation was not previously started on this context via
+ * \c psa_sign_hash_start().
+ *
+ * \retval #PSA_ERROR_NOT_SUPPORTED
+ * \retval #PSA_ERROR_INVALID_ARGUMENT
+ * \retval #PSA_ERROR_INSUFFICIENT_MEMORY
+ * \retval #PSA_ERROR_COMMUNICATION_FAILURE
+ * \retval #PSA_ERROR_HARDWARE_FAILURE
+ * \retval #PSA_ERROR_CORRUPTION_DETECTED
+ * \retval #PSA_ERROR_STORAGE_FAILURE
+ * \retval #PSA_ERROR_DATA_CORRUPT
+ * \retval #PSA_ERROR_DATA_INVALID
+ * \retval #PSA_ERROR_INSUFFICIENT_ENTROPY
+ * \retval #PSA_ERROR_BAD_STATE
+ * The library has either not been previously initialized by
+ * psa_crypto_init() or you did not previously call
+ * psa_sign_hash_start() with this operation object. It is
+ * implementation-dependent whether a failure to initialize results in
+ * this error code.
+ */
+psa_status_t psa_sign_hash_complete(
+ psa_sign_hash_interruptible_operation_t *operation,
+ uint8_t *signature, size_t signature_size,
+ size_t *signature_length);
+
+/**
+ * \brief Abort a sign hash operation.
+ *
+ * \warning This is a beta API, and thus subject to change
+ * at any point. It is not bound by the usual
+ * interface stability promises.
+ *
+ * \note This function is the only function that clears
+ * the number of ops completed as part of the
+ * operation. Please ensure you copy this value via
+ * \c psa_sign_hash_get_num_ops() if required
+ * before calling.
+ *
+ * \note Aborting an operation frees all associated
+ * resources except for the \p operation structure
+ * itself. Once aborted, the operation object can
+ * be reused for another operation by calling \c
+ * psa_sign_hash_start() again.
+ *
+ * \note You may call this function any time after the
+ * operation object has been initialized. In
+ * particular, calling \c psa_sign_hash_abort()
+ * after the operation has already been terminated
+ * by a call to \c psa_sign_hash_abort() or
+ * psa_sign_hash_complete() is safe.
+ *
+ * \param[in,out] operation Initialized sign hash operation.
+ *
+ * \retval #PSA_SUCCESS
+ * The operation was aborted successfully.
+ *
+ * \retval #PSA_ERROR_NOT_SUPPORTED
+ * \retval #PSA_ERROR_BAD_STATE
+ * The library has not been previously initialized by psa_crypto_init().
+ * It is implementation-dependent whether a failure to initialize
+ * results in this error code.
+ */
+psa_status_t psa_sign_hash_abort(
+ psa_sign_hash_interruptible_operation_t *operation);
+
+/**
+ * \brief Start reading and verifying a hash or short
+ * message, in an interruptible manner.
+ *
+ * \see \c psa_verify_hash_complete()
+ *
+ * \warning This is a beta API, and thus subject to change
+ * at any point. It is not bound by the usual
+ * interface stability promises.
+ *
+ * \note This function combined with \c
+ * psa_verify_hash_complete() is equivalent to
+ * \c psa_verify_hash() but \c
+ * psa_verify_hash_complete() can return early and
+ * resume according to the limit set with \c
+ * psa_interruptible_set_max_ops() to reduce the
+ * maximum time spent in a function.
+ *
+ * \note Users should call \c psa_verify_hash_complete()
+ * repeatedly on the same operation object after a
+ * successful call to this function until \c
+ * psa_verify_hash_complete() either returns 0 or
+ * an error. \c psa_verify_hash_complete() will
+ * return #PSA_OPERATION_INCOMPLETE if there is
+ * more work to do. Alternatively users can call
+ * \c psa_verify_hash_abort() at any point if they
+ * no longer want the result.
+ *
+ * \note If this function returns an error status, the
+ * operation enters an error state and must be
+ * aborted by calling \c psa_verify_hash_abort().
+ *
+ * \param[in, out] operation The \c psa_verify_hash_interruptible_operation_t
+ * to use. This must be initialized first.
+ *
+ * \param key Identifier of the key to use for the operation.
+ * The key must allow the usage
+ * #PSA_KEY_USAGE_VERIFY_HASH.
+ * \param alg A signature algorithm (\c PSA_ALG_XXX
+ * value such that #PSA_ALG_IS_SIGN_HASH(\p alg)
+ * is true), that is compatible with
+ * the type of \p key.
+ * \param[in] hash The hash whose signature is to be verified.
+ * \param hash_length Size of the \p hash buffer in bytes.
+ * \param[in] signature Buffer containing the signature to verify.
+ * \param signature_length Size of the \p signature buffer in bytes.
+ *
+ * \retval #PSA_SUCCESS
+ * The operation started successfully - please call \c
+ * psa_verify_hash_complete() with the same context to complete the
+ * operation.
+ *
+ * \retval #PSA_ERROR_BAD_STATE
+ * Another operation has already been started on this context, and is
+ * still in progress.
+ *
+ * \retval #PSA_ERROR_NOT_PERMITTED
+ * The key does not have the #PSA_KEY_USAGE_VERIFY_HASH flag, or it does
+ * not permit the requested algorithm.
+ *
+ * \retval #PSA_ERROR_NOT_SUPPORTED
+ * \retval #PSA_ERROR_INVALID_ARGUMENT
+ * \retval #PSA_ERROR_INSUFFICIENT_MEMORY
+ * \retval #PSA_ERROR_COMMUNICATION_FAILURE
+ * \retval #PSA_ERROR_HARDWARE_FAILURE
+ * \retval #PSA_ERROR_CORRUPTION_DETECTED
+ * \retval #PSA_ERROR_STORAGE_FAILURE
+ * \retval PSA_ERROR_DATA_CORRUPT
+ * \retval PSA_ERROR_DATA_INVALID
+ * \retval #PSA_ERROR_BAD_STATE
+ * The library has not been previously initialized by psa_crypto_init().
+ * It is implementation-dependent whether a failure to initialize
+ * results in this error code.
+ */
+psa_status_t psa_verify_hash_start(
+ psa_verify_hash_interruptible_operation_t *operation,
+ mbedtls_svc_key_id_t key, psa_algorithm_t alg,
+ const uint8_t *hash, size_t hash_length,
+ const uint8_t *signature, size_t signature_length);
+
+/**
+ * \brief Continue and eventually complete the action of
+ * reading and verifying a hash or short message
+ * signed with a private key, in an interruptible
+ * manner.
+ *
+ * \see \c psa_verify_hash_start()
+ *
+ * \warning This is a beta API, and thus subject to change
+ * at any point. It is not bound by the usual
+ * interface stability promises.
+ *
+ * \note This function combined with \c
+ * psa_verify_hash_start() is equivalent to
+ * \c psa_verify_hash() but this function can
+ * return early and resume according to the limit
+ * set with \c psa_interruptible_set_max_ops() to
+ * reduce the maximum time spent in a function
+ * call.
+ *
+ * \note Users should call this function on the same
+ * operation object repeatedly until it either
+ * returns 0 or an error. This function will return
+ * #PSA_OPERATION_INCOMPLETE if there is more work
+ * to do. Alternatively users can call
+ * \c psa_verify_hash_abort() at any point if they
+ * no longer want the result.
+ *
+ * \note When this function returns successfully, the
+ * operation becomes inactive. If this function
+ * returns an error status, the operation enters an
+ * error state and must be aborted by calling
+ * \c psa_verify_hash_abort().
+ *
+ * \param[in, out] operation The \c psa_verify_hash_interruptible_operation_t
+ * to use. This must be initialized first, and have
+ * had \c psa_verify_hash_start() called with it
+ * first.
+ *
+ * \retval #PSA_SUCCESS
+ * Operation completed successfully, and the passed signature is valid.
+ *
+ * \retval #PSA_OPERATION_INCOMPLETE
+ * Operation was interrupted due to the setting of \c
+ * psa_interruptible_set_max_ops(). There is still work to be done.
+ * Call this function again with the same operation object.
+ *
+ * \retval #PSA_ERROR_INVALID_HANDLE
+ * \retval #PSA_ERROR_INVALID_SIGNATURE
+ * The calculation was performed successfully, but the passed
+ * signature is not a valid signature.
+ *\retval #PSA_ERROR_BAD_STATE
+ * An operation was not previously started on this context via
+ * \c psa_verify_hash_start().
+ * \retval #PSA_ERROR_NOT_SUPPORTED
+ * \retval #PSA_ERROR_INVALID_ARGUMENT
+ * \retval #PSA_ERROR_INSUFFICIENT_MEMORY
+ * \retval #PSA_ERROR_COMMUNICATION_FAILURE
+ * \retval #PSA_ERROR_HARDWARE_FAILURE
+ * \retval #PSA_ERROR_CORRUPTION_DETECTED
+ * \retval #PSA_ERROR_STORAGE_FAILURE
+ * \retval #PSA_ERROR_DATA_CORRUPT
+ * \retval #PSA_ERROR_DATA_INVALID
+ * \retval #PSA_ERROR_INSUFFICIENT_ENTROPY
+ * \retval #PSA_ERROR_BAD_STATE
+ * The library has either not been previously initialized by
+ * psa_crypto_init() or you did not previously call
+ * psa_verify_hash_start() on this object. It is
+ * implementation-dependent whether a failure to initialize results in
+ * this error code.
+ */
+psa_status_t psa_verify_hash_complete(
+ psa_verify_hash_interruptible_operation_t *operation);
+
+/**
+ * \brief Abort a verify hash operation.
+ *
+ * \warning This is a beta API, and thus subject to change at
+ * any point. It is not bound by the usual interface
+ * stability promises.
+ *
+ * \note This function is the only function that clears the
+ * number of ops completed as part of the operation.
+ * Please ensure you copy this value via
+ * \c psa_verify_hash_get_num_ops() if required
+ * before calling.
+ *
+ * \note Aborting an operation frees all associated
+ * resources except for the operation structure
+ * itself. Once aborted, the operation object can be
+ * reused for another operation by calling \c
+ * psa_verify_hash_start() again.
+ *
+ * \note You may call this function any time after the
+ * operation object has been initialized.
+ * In particular, calling \c psa_verify_hash_abort()
+ * after the operation has already been terminated by
+ * a call to \c psa_verify_hash_abort() or
+ * psa_verify_hash_complete() is safe.
+ *
+ * \param[in,out] operation Initialized verify hash operation.
+ *
+ * \retval #PSA_SUCCESS
+ * The operation was aborted successfully.
+ *
+ * \retval #PSA_ERROR_NOT_SUPPORTED
+ * \retval #PSA_ERROR_BAD_STATE
+ * The library has not been previously initialized by psa_crypto_init().
+ * It is implementation-dependent whether a failure to initialize
+ * results in this error code.
+ */
+psa_status_t psa_verify_hash_abort(
+ psa_verify_hash_interruptible_operation_t *operation);
+
+
+/**@}*/
+
#ifdef __cplusplus
}
#endif
diff --git a/include/psa/crypto_builtin_composites.h b/include/psa/crypto_builtin_composites.h
index b7f0b1162..9f23551eb 100644
--- a/include/psa/crypto_builtin_composites.h
+++ b/include/psa/crypto_builtin_composites.h
@@ -107,4 +107,78 @@ typedef struct {
#define MBEDTLS_PSA_AEAD_OPERATION_INIT { 0, 0, 0, 0, { 0 } }
+#include "mbedtls/ecdsa.h"
+
+/* Context structure for the Mbed TLS interruptible sign hash implementation. */
+typedef struct {
+#if (defined(MBEDTLS_PSA_BUILTIN_ALG_ECDSA) || \
+ defined(MBEDTLS_PSA_BUILTIN_ALG_DETERMINISTIC_ECDSA)) && \
+ defined(MBEDTLS_ECP_RESTARTABLE)
+ mbedtls_ecdsa_context *MBEDTLS_PRIVATE(ctx);
+ mbedtls_ecdsa_restart_ctx MBEDTLS_PRIVATE(restart_ctx);
+
+ uint32_t MBEDTLS_PRIVATE(num_ops);
+
+ size_t MBEDTLS_PRIVATE(coordinate_bytes);
+ psa_algorithm_t MBEDTLS_PRIVATE(alg);
+ mbedtls_md_type_t MBEDTLS_PRIVATE(md_alg);
+ uint8_t MBEDTLS_PRIVATE(hash)[PSA_BITS_TO_BYTES(PSA_VENDOR_ECC_MAX_CURVE_BITS)];
+ size_t MBEDTLS_PRIVATE(hash_length);
+
+#else
+ /* Make the struct non-empty if algs not supported. */
+ unsigned MBEDTLS_PRIVATE(dummy);
+
+#endif /* defined(MBEDTLS_PSA_BUILTIN_ALG_ECDSA) ||
+ * defined(MBEDTLS_PSA_BUILTIN_ALG_DETERMINISTIC_ECDSA) &&
+ * defined( MBEDTLS_ECP_RESTARTABLE ) */
+} mbedtls_psa_sign_hash_interruptible_operation_t;
+
+#if (defined(MBEDTLS_PSA_BUILTIN_ALG_ECDSA) || \
+ defined(MBEDTLS_PSA_BUILTIN_ALG_DETERMINISTIC_ECDSA)) && \
+ defined(MBEDTLS_ECP_RESTARTABLE)
+#define MBEDTLS_PSA_SIGN_HASH_INTERRUPTIBLE_OPERATION_INIT { { 0 }, { 0 }, 0, 0, 0, 0, 0, 0 }
+#else
+#define MBEDTLS_PSA_SIGN_HASH_INTERRUPTIBLE_OPERATION_INIT { 0 }
+#endif
+
+/* Context structure for the Mbed TLS interruptible verify hash
+ * implementation.*/
+typedef struct {
+#if (defined(MBEDTLS_PSA_BUILTIN_ALG_ECDSA) || \
+ defined(MBEDTLS_PSA_BUILTIN_ALG_DETERMINISTIC_ECDSA)) && \
+ defined(MBEDTLS_ECP_RESTARTABLE)
+
+ mbedtls_ecdsa_context *MBEDTLS_PRIVATE(ctx);
+ mbedtls_ecdsa_restart_ctx MBEDTLS_PRIVATE(restart_ctx);
+
+ uint32_t MBEDTLS_PRIVATE(num_ops);
+
+ uint8_t MBEDTLS_PRIVATE(hash)[PSA_BITS_TO_BYTES(PSA_VENDOR_ECC_MAX_CURVE_BITS)];
+ size_t MBEDTLS_PRIVATE(hash_length);
+
+ mbedtls_mpi MBEDTLS_PRIVATE(r);
+ mbedtls_mpi MBEDTLS_PRIVATE(s);
+
+#else
+ /* Make the struct non-empty if algs not supported. */
+ unsigned MBEDTLS_PRIVATE(dummy);
+
+#endif /* defined(MBEDTLS_PSA_BUILTIN_ALG_ECDSA) ||
+ * defined(MBEDTLS_PSA_BUILTIN_ALG_DETERMINISTIC_ECDSA) &&
+ * defined( MBEDTLS_ECP_RESTARTABLE ) */
+
+} mbedtls_psa_verify_hash_interruptible_operation_t;
+
+#if (defined(MBEDTLS_PSA_BUILTIN_ALG_ECDSA) || \
+ defined(MBEDTLS_PSA_BUILTIN_ALG_DETERMINISTIC_ECDSA)) && \
+ defined(MBEDTLS_ECP_RESTARTABLE)
+#define MBEDTLS_VERIFY_SIGN_HASH_INTERRUPTIBLE_OPERATION_INIT { { 0 }, { 0 }, 0, 0, 0, 0, { 0 }, \
+ { 0 } }
+#else
+#define MBEDTLS_VERIFY_SIGN_HASH_INTERRUPTIBLE_OPERATION_INIT { 0 }
+#endif
+
+
+
#endif /* PSA_CRYPTO_BUILTIN_COMPOSITES_H */
diff --git a/include/psa/crypto_driver_contexts_composites.h b/include/psa/crypto_driver_contexts_composites.h
index bcd000e70..1b95814f9 100644
--- a/include/psa/crypto_driver_contexts_composites.h
+++ b/include/psa/crypto_driver_contexts_composites.h
@@ -114,5 +114,15 @@ typedef union {
#endif
} psa_driver_aead_context_t;
+typedef union {
+ unsigned dummy; /* Make sure this union is always non-empty */
+ mbedtls_psa_sign_hash_interruptible_operation_t mbedtls_ctx;
+} psa_driver_sign_hash_interruptible_context_t;
+
+typedef union {
+ unsigned dummy; /* Make sure this union is always non-empty */
+ mbedtls_psa_verify_hash_interruptible_operation_t mbedtls_ctx;
+} psa_driver_verify_hash_interruptible_context_t;
+
#endif /* PSA_CRYPTO_DRIVER_CONTEXTS_COMPOSITES_H */
/* End of automatically generated file. */
diff --git a/include/psa/crypto_struct.h b/include/psa/crypto_struct.h
index 7a6caa2ed..934bc176e 100644
--- a/include/psa/crypto_struct.h
+++ b/include/psa/crypto_struct.h
@@ -491,6 +491,66 @@ static inline size_t psa_get_key_bits(
return attributes->MBEDTLS_PRIVATE(core).MBEDTLS_PRIVATE(bits);
}
+/**
+ * \brief The context for PSA interruptible hash signing.
+ */
+struct psa_sign_hash_interruptible_operation_s {
+ /** Unique ID indicating which driver got assigned to do the
+ * operation. Since driver contexts are driver-specific, swapping
+ * drivers halfway through the operation is not supported.
+ * ID values are auto-generated in psa_crypto_driver_wrappers.h
+ * ID value zero means the context is not valid or not assigned to
+ * any driver (i.e. none of the driver contexts are active). */
+ unsigned int MBEDTLS_PRIVATE(id);
+
+ psa_driver_sign_hash_interruptible_context_t MBEDTLS_PRIVATE(ctx);
+
+ unsigned int MBEDTLS_PRIVATE(error_occurred) : 1;
+
+ uint32_t MBEDTLS_PRIVATE(num_ops);
+};
+
+#define PSA_SIGN_HASH_INTERRUPTIBLE_OPERATION_INIT { 0, { 0 }, 0, 0 }
+
+static inline struct psa_sign_hash_interruptible_operation_s
+psa_sign_hash_interruptible_operation_init(void)
+{
+ const struct psa_sign_hash_interruptible_operation_s v =
+ PSA_SIGN_HASH_INTERRUPTIBLE_OPERATION_INIT;
+
+ return v;
+}
+
+/**
+ * \brief The context for PSA interruptible hash verification.
+ */
+struct psa_verify_hash_interruptible_operation_s {
+ /** Unique ID indicating which driver got assigned to do the
+ * operation. Since driver contexts are driver-specific, swapping
+ * drivers halfway through the operation is not supported.
+ * ID values are auto-generated in psa_crypto_driver_wrappers.h
+ * ID value zero means the context is not valid or not assigned to
+ * any driver (i.e. none of the driver contexts are active). */
+ unsigned int MBEDTLS_PRIVATE(id);
+
+ psa_driver_verify_hash_interruptible_context_t MBEDTLS_PRIVATE(ctx);
+
+ unsigned int MBEDTLS_PRIVATE(error_occurred) : 1;
+
+ uint32_t MBEDTLS_PRIVATE(num_ops);
+};
+
+#define PSA_VERIFY_HASH_INTERRUPTIBLE_OPERATION_INIT { 0, { 0 }, 0, 0 }
+
+static inline struct psa_verify_hash_interruptible_operation_s
+psa_verify_hash_interruptible_operation_init(void)
+{
+ const struct psa_verify_hash_interruptible_operation_s v =
+ PSA_VERIFY_HASH_INTERRUPTIBLE_OPERATION_INIT;
+
+ return v;
+}
+
#ifdef __cplusplus
}
#endif
diff --git a/include/psa/crypto_values.h b/include/psa/crypto_values.h
index ee95745ad..39acd96c5 100644
--- a/include/psa/crypto_values.h
+++ b/include/psa/crypto_values.h
@@ -335,6 +335,13 @@
*/
#define PSA_ERROR_DATA_INVALID ((psa_status_t)-153)
+/** The function that returns this status is defined as interruptible and
+ * still has work to do, thus the user should call the function again with the
+ * same operation context until it either returns #PSA_SUCCESS or any other
+ * error. This is not an error per se, more a notification of status.
+ */
+#define PSA_OPERATION_INCOMPLETE ((psa_status_t)-248)
+
/* *INDENT-ON* */
/**@}*/
@@ -2739,4 +2746,18 @@ static inline int mbedtls_svc_key_id_is_null(mbedtls_svc_key_id_t key)
/**@}*/
+/**@}*/
+
+/** \defgroup interruptible Interruptible operations
+ * @{
+ */
+
+/** Maximum value for use with \c psa_interruptible_set_max_ops() to determine
+ * the maximum number of ops allowed to be executed by an interruptible
+ * function in a single call.
+ */
+#define PSA_INTERRUPTIBLE_MAX_OPS_UNLIMITED UINT32_MAX
+
+/**@}*/
+
#endif /* PSA_CRYPTO_VALUES_H */
diff --git a/library/ecdsa.c b/library/ecdsa.c
index 3ddb82b1e..eb3c30319 100644
--- a/library/ecdsa.c
+++ b/library/ecdsa.c
@@ -239,13 +239,13 @@ cleanup:
* Compute ECDSA signature of a hashed message (SEC1 4.1.3)
* Obviously, compared to SEC1 4.1.3, we skip step 4 (hash message)
*/
-static int ecdsa_sign_restartable(mbedtls_ecp_group *grp,
- mbedtls_mpi *r, mbedtls_mpi *s,
- const mbedtls_mpi *d, const unsigned char *buf, size_t blen,
- int (*f_rng)(void *, unsigned char *, size_t), void *p_rng,
- int (*f_rng_blind)(void *, unsigned char *, size_t),
- void *p_rng_blind,
- mbedtls_ecdsa_restart_ctx *rs_ctx)
+int mbedtls_ecdsa_sign_restartable(mbedtls_ecp_group *grp,
+ mbedtls_mpi *r, mbedtls_mpi *s,
+ const mbedtls_mpi *d, const unsigned char *buf, size_t blen,
+ int (*f_rng)(void *, unsigned char *, size_t), void *p_rng,
+ int (*f_rng_blind)(void *, unsigned char *, size_t),
+ void *p_rng_blind,
+ mbedtls_ecdsa_restart_ctx *rs_ctx)
{
int ret, key_tries, sign_tries;
int *p_sign_tries = &sign_tries, *p_key_tries = &key_tries;
@@ -394,8 +394,8 @@ int mbedtls_ecdsa_sign(mbedtls_ecp_group *grp, mbedtls_mpi *r, mbedtls_mpi *s,
int (*f_rng)(void *, unsigned char *, size_t), void *p_rng)
{
/* Use the same RNG for both blinding and ephemeral key generation */
- return ecdsa_sign_restartable(grp, r, s, d, buf, blen,
- f_rng, p_rng, f_rng, p_rng, NULL);
+ return mbedtls_ecdsa_sign_restartable(grp, r, s, d, buf, blen,
+ f_rng, p_rng, f_rng, p_rng, NULL);
}
#endif /* !MBEDTLS_ECDSA_SIGN_ALT */
@@ -406,13 +406,13 @@ int mbedtls_ecdsa_sign(mbedtls_ecp_group *grp, mbedtls_mpi *r, mbedtls_mpi *s,
* note: The f_rng_blind parameter must not be NULL.
*
*/
-static int ecdsa_sign_det_restartable(mbedtls_ecp_group *grp,
- mbedtls_mpi *r, mbedtls_mpi *s,
- const mbedtls_mpi *d, const unsigned char *buf, size_t blen,
- mbedtls_md_type_t md_alg,
- int (*f_rng_blind)(void *, unsigned char *, size_t),
- void *p_rng_blind,
- mbedtls_ecdsa_restart_ctx *rs_ctx)
+int mbedtls_ecdsa_sign_det_restartable(mbedtls_ecp_group *grp,
+ mbedtls_mpi *r, mbedtls_mpi *s,
+ const mbedtls_mpi *d, const unsigned char *buf, size_t blen,
+ mbedtls_md_type_t md_alg,
+ int (*f_rng_blind)(void *, unsigned char *, size_t),
+ void *p_rng_blind,
+ mbedtls_ecdsa_restart_ctx *rs_ctx)
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
mbedtls_hmac_drbg_context rng_ctx;
@@ -462,9 +462,9 @@ sign:
ret = mbedtls_ecdsa_sign(grp, r, s, d, buf, blen,
mbedtls_hmac_drbg_random, p_rng);
#else
- ret = ecdsa_sign_restartable(grp, r, s, d, buf, blen,
- mbedtls_hmac_drbg_random, p_rng,
- f_rng_blind, p_rng_blind, rs_ctx);
+ ret = mbedtls_ecdsa_sign_restartable(grp, r, s, d, buf, blen,
+ mbedtls_hmac_drbg_random, p_rng,
+ f_rng_blind, p_rng_blind, rs_ctx);
#endif /* MBEDTLS_ECDSA_SIGN_ALT */
cleanup:
@@ -487,8 +487,8 @@ int mbedtls_ecdsa_sign_det_ext(mbedtls_ecp_group *grp, mbedtls_mpi *r,
size_t),
void *p_rng_blind)
{
- return ecdsa_sign_det_restartable(grp, r, s, d, buf, blen, md_alg,
- f_rng_blind, p_rng_blind, NULL);
+ return mbedtls_ecdsa_sign_det_restartable(grp, r, s, d, buf, blen, md_alg,
+ f_rng_blind, p_rng_blind, NULL);
}
#endif /* MBEDTLS_ECDSA_DETERMINISTIC */
@@ -497,11 +497,12 @@ int mbedtls_ecdsa_sign_det_ext(mbedtls_ecp_group *grp, mbedtls_mpi *r,
* Verify ECDSA signature of hashed message (SEC1 4.1.4)
* Obviously, compared to SEC1 4.1.3, we skip step 2 (hash message)
*/
-static int ecdsa_verify_restartable(mbedtls_ecp_group *grp,
- const unsigned char *buf, size_t blen,
- const mbedtls_ecp_point *Q,
- const mbedtls_mpi *r, const mbedtls_mpi *s,
- mbedtls_ecdsa_restart_ctx *rs_ctx)
+int mbedtls_ecdsa_verify_restartable(mbedtls_ecp_group *grp,
+ const unsigned char *buf, size_t blen,
+ const mbedtls_ecp_point *Q,
+ const mbedtls_mpi *r,
+ const mbedtls_mpi *s,
+ mbedtls_ecdsa_restart_ctx *rs_ctx)
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
mbedtls_mpi e, s_inv, u1, u2;
@@ -610,7 +611,7 @@ int mbedtls_ecdsa_verify(mbedtls_ecp_group *grp,
const mbedtls_mpi *r,
const mbedtls_mpi *s)
{
- return ecdsa_verify_restartable(grp, buf, blen, Q, r, s, NULL);
+ return mbedtls_ecdsa_verify_restartable(grp, buf, blen, Q, r, s, NULL);
}
#endif /* !MBEDTLS_ECDSA_VERIFY_ALT */
@@ -665,9 +666,9 @@ int mbedtls_ecdsa_write_signature_restartable(mbedtls_ecdsa_context *ctx,
mbedtls_mpi_init(&s);
#if defined(MBEDTLS_ECDSA_DETERMINISTIC)
- MBEDTLS_MPI_CHK(ecdsa_sign_det_restartable(&ctx->grp, &r, &s, &ctx->d,
- hash, hlen, md_alg, f_rng,
- p_rng, rs_ctx));
+ MBEDTLS_MPI_CHK(mbedtls_ecdsa_sign_det_restartable(&ctx->grp, &r, &s, &ctx->d,
+ hash, hlen, md_alg, f_rng,
+ p_rng, rs_ctx));
#else
(void) md_alg;
@@ -678,9 +679,9 @@ int mbedtls_ecdsa_write_signature_restartable(mbedtls_ecdsa_context *ctx,
hash, hlen, f_rng, p_rng));
#else
/* Use the same RNG for both blinding and ephemeral key generation */
- MBEDTLS_MPI_CHK(ecdsa_sign_restartable(&ctx->grp, &r, &s, &ctx->d,
- hash, hlen, f_rng, p_rng, f_rng,
- p_rng, rs_ctx));
+ MBEDTLS_MPI_CHK(mbedtls_ecdsa_sign_restartable(&ctx->grp, &r, &s, &ctx->d,
+ hash, hlen, f_rng, p_rng, f_rng,
+ p_rng, rs_ctx));
#endif /* MBEDTLS_ECDSA_SIGN_ALT */
#endif /* MBEDTLS_ECDSA_DETERMINISTIC */
@@ -760,8 +761,8 @@ int mbedtls_ecdsa_read_signature_restartable(mbedtls_ecdsa_context *ctx,
goto cleanup;
}
#else
- if ((ret = ecdsa_verify_restartable(&ctx->grp, hash, hlen,
- &ctx->Q, &r, &s, rs_ctx)) != 0) {
+ if ((ret = mbedtls_ecdsa_verify_restartable(&ctx->grp, hash, hlen,
+ &ctx->Q, &r, &s, rs_ctx)) != 0) {
goto cleanup;
}
#endif /* MBEDTLS_ECDSA_VERIFY_ALT */
diff --git a/library/psa_crypto.c b/library/psa_crypto.c
index a683fdb8f..3ec9273de 100644
--- a/library/psa_crypto.c
+++ b/library/psa_crypto.c
@@ -81,6 +81,7 @@
#include "mbedtls/sha1.h"
#include "mbedtls/sha256.h"
#include "mbedtls/sha512.h"
+#include "hash_info.h"
#define ARRAY_LENGTH(array) (sizeof(array) / sizeof(*(array)))
@@ -310,6 +311,9 @@ psa_status_t mbedtls_to_psa_error(int ret)
case MBEDTLS_ERR_ECP_RANDOM_FAILED:
return PSA_ERROR_INSUFFICIENT_ENTROPY;
+ case MBEDTLS_ERR_ECP_IN_PROGRESS:
+ return PSA_OPERATION_INCOMPLETE;
+
case MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED:
return PSA_ERROR_CORRUPTION_DETECTED;
@@ -2679,6 +2683,37 @@ static psa_status_t psa_sign_verify_check_alg(int input_is_message,
return PSA_SUCCESS;
}
+/**
+ * \brief Fill the unused part of the output buffer (the
+ * whole buffer on error, the trailing part on
+ * success) with something that isn't a valid
+ * signature (barring an attack on the signature
+ * and deliberately-crafted input), in case the
+ * caller doesn't check the return status properly.
+ *
+ * \param output_buffer pointer to buffer to wipe. May not be NULL
+ * unless \p output_buffer_size is zero.
+ * \param status status of function called to generate
+ * output_buffer originally
+ * \param output_buffer_size Size of output buffer. If zero, \p output_buffer
+ * could be NULL
+ * \param output_buffer_length Length of data written to output_buffer, must be
+ * less than \p output_buffer_size
+ */
+static void psa_wipe_output_buffer(uint8_t *output_buffer, psa_status_t status,
+ size_t output_buffer_size, size_t output_buffer_length)
+{
+ if (status == PSA_SUCCESS) {
+ memset(output_buffer + output_buffer_length, '!',
+ output_buffer_size - output_buffer_length);
+ } else if (output_buffer_size > 0) {
+ memset(output_buffer, '!', output_buffer_size);
+ }
+ /* If output_buffer_size is 0 then we have nothing to do. We must
+ * not call memset because output_buffer may be NULL in this
+ * case.*/
+}
+
static psa_status_t psa_sign_internal(mbedtls_svc_key_id_t key,
int input_is_message,
psa_algorithm_t alg,
@@ -2741,18 +2776,8 @@ static psa_status_t psa_sign_internal(mbedtls_svc_key_id_t key,
exit:
- /* Fill the unused part of the output buffer (the whole buffer on error,
- * the trailing part on success) with something that isn't a valid signature
- * (barring an attack on the signature and deliberately-crafted input),
- * in case the caller doesn't check the return status properly. */
- if (status == PSA_SUCCESS) {
- memset(signature + *signature_length, '!',
- signature_size - *signature_length);
- } else {
- memset(signature, '!', signature_size);
- }
- /* If signature_size is 0 then we have nothing to do. We must not call
- * memset because signature may be NULL in this case. */
+ psa_wipe_output_buffer(signature, status, signature_size,
+ *signature_length);
unlock_status = psa_unlock_key_slot(slot);
@@ -3124,7 +3149,766 @@ exit:
return (status == PSA_SUCCESS) ? unlock_status : status;
}
+/****************************************************************/
+/* Asymmetric interruptible cryptography */
+/****************************************************************/
+void psa_interruptible_set_max_ops(uint32_t max_ops)
+{
+ psa_driver_wrapper_interruptible_set_max_ops(max_ops);
+}
+
+uint32_t psa_interruptible_get_max_ops(void)
+{
+ return psa_driver_wrapper_interruptible_get_max_ops();
+}
+
+
+uint32_t psa_sign_hash_get_num_ops(
+ const psa_sign_hash_interruptible_operation_t *operation)
+{
+ return operation->num_ops;
+}
+
+uint32_t psa_verify_hash_get_num_ops(
+ const psa_verify_hash_interruptible_operation_t *operation)
+{
+ return operation->num_ops;
+}
+
+static psa_status_t psa_sign_hash_abort_internal(
+ psa_sign_hash_interruptible_operation_t *operation)
+{
+ if (operation->id == 0) {
+ /* The object has (apparently) been initialized but it is not (yet)
+ * in use. It's ok to call abort on such an object, and there's
+ * nothing to do. */
+ return PSA_SUCCESS;
+ }
+
+ psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+
+ status = psa_driver_wrapper_sign_hash_abort(operation);
+
+ operation->id = 0;
+
+ /* Do not clear either the error_occurred or num_ops elements here as they
+ * only want to be cleared by the application calling abort, not by abort
+ * being called at completion of an operation. */
+
+ return status;
+}
+
+psa_status_t psa_sign_hash_start(
+ psa_sign_hash_interruptible_operation_t *operation,
+ mbedtls_svc_key_id_t key, psa_algorithm_t alg,
+ const uint8_t *hash, size_t hash_length)
+{
+ psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+ psa_status_t unlock_status = PSA_ERROR_CORRUPTION_DETECTED;
+ psa_key_slot_t *slot;
+
+ /* Check that start has not been previously called, or operation has not
+ * previously errored. */
+ if (operation->id != 0 || operation->error_occurred) {
+ return PSA_ERROR_BAD_STATE;
+ }
+
+ status = psa_sign_verify_check_alg(0, alg);
+ if (status != PSA_SUCCESS) {
+ operation->error_occurred = 1;
+ return status;
+ }
+
+ status = psa_get_and_lock_key_slot_with_policy(key, &slot,
+ PSA_KEY_USAGE_SIGN_HASH,
+ alg);
+
+ if (status != PSA_SUCCESS) {
+ goto exit;
+ }
+
+ if (!PSA_KEY_TYPE_IS_KEY_PAIR(slot->attr.type)) {
+ status = PSA_ERROR_INVALID_ARGUMENT;
+ goto exit;
+ }
+
+ psa_key_attributes_t attributes = {
+ .core = slot->attr
+ };
+
+ /* Ensure ops count gets reset, in case of operation re-use. */
+ operation->num_ops = 0;
+
+ status = psa_driver_wrapper_sign_hash_start(operation, &attributes,
+ slot->key.data,
+ slot->key.bytes, alg,
+ hash, hash_length);
+exit:
+
+ if (status != PSA_SUCCESS) {
+ operation->error_occurred = 1;
+ psa_sign_hash_abort_internal(operation);
+ }
+
+ unlock_status = psa_unlock_key_slot(slot);
+
+ if (unlock_status != PSA_SUCCESS) {
+ operation->error_occurred = 1;
+ }
+
+ return (status == PSA_SUCCESS) ? unlock_status : status;
+}
+
+
+psa_status_t psa_sign_hash_complete(
+ psa_sign_hash_interruptible_operation_t *operation,
+ uint8_t *signature, size_t signature_size,
+ size_t *signature_length)
+{
+ psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+
+ *signature_length = 0;
+
+ /* Check that start has been called first, and that operation has not
+ * previously errored. */
+ if (operation->id == 0 || operation->error_occurred) {
+ status = PSA_ERROR_BAD_STATE;
+ goto exit;
+ }
+
+ /* Immediately reject a zero-length signature buffer. This guarantees that
+ * signature must be a valid pointer. */
+ if (signature_size == 0) {
+ status = PSA_ERROR_BUFFER_TOO_SMALL;
+ goto exit;
+ }
+
+ status = psa_driver_wrapper_sign_hash_complete(operation, signature,
+ signature_size,
+ signature_length);
+
+ /* Update ops count with work done. */
+ operation->num_ops = psa_driver_wrapper_sign_hash_get_num_ops(operation);
+
+exit:
+
+ psa_wipe_output_buffer(signature, status, signature_size,
+ *signature_length);
+
+ if (status != PSA_OPERATION_INCOMPLETE) {
+ if (status != PSA_SUCCESS) {
+ operation->error_occurred = 1;
+ }
+
+ psa_sign_hash_abort_internal(operation);
+ }
+
+ return status;
+}
+
+psa_status_t psa_sign_hash_abort(
+ psa_sign_hash_interruptible_operation_t *operation)
+{
+ psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+
+ status = psa_sign_hash_abort_internal(operation);
+
+ /* We clear the number of ops done here, so that it is not cleared when
+ * the operation fails or succeeds, only on manual abort. */
+ operation->num_ops = 0;
+
+ /* Likewise, failure state. */
+ operation->error_occurred = 0;
+
+ return status;
+}
+
+static psa_status_t psa_verify_hash_abort_internal(
+ psa_verify_hash_interruptible_operation_t *operation)
+{
+ if (operation->id == 0) {
+ /* The object has (apparently) been initialized but it is not (yet)
+ * in use. It's ok to call abort on such an object, and there's
+ * nothing to do. */
+ return PSA_SUCCESS;
+ }
+
+ psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+
+ status = psa_driver_wrapper_verify_hash_abort(operation);
+
+ operation->id = 0;
+
+ /* Do not clear either the error_occurred or num_ops elements here as they
+ * only want to be cleared by the application calling abort, not by abort
+ * being called at completion of an operation. */
+
+ return status;
+}
+
+psa_status_t psa_verify_hash_start(
+ psa_verify_hash_interruptible_operation_t *operation,
+ mbedtls_svc_key_id_t key, psa_algorithm_t alg,
+ const uint8_t *hash, size_t hash_length,
+ const uint8_t *signature, size_t signature_length)
+{
+ psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+ psa_status_t unlock_status = PSA_ERROR_CORRUPTION_DETECTED;
+ psa_key_slot_t *slot;
+
+ /* Check that start has not been previously called, or operation has not
+ * previously errored. */
+ if (operation->id != 0 || operation->error_occurred) {
+ return PSA_ERROR_BAD_STATE;
+ }
+
+ status = psa_sign_verify_check_alg(0, alg);
+ if (status != PSA_SUCCESS) {
+ operation->error_occurred = 1;
+ return status;
+ }
+
+ status = psa_get_and_lock_key_slot_with_policy(key, &slot,
+ PSA_KEY_USAGE_VERIFY_HASH,
+ alg);
+
+ if (status != PSA_SUCCESS) {
+ operation->error_occurred = 1;
+ return status;
+ }
+
+ psa_key_attributes_t attributes = {
+ .core = slot->attr
+ };
+
+ /* Ensure ops count gets reset, in case of operation re-use. */
+ operation->num_ops = 0;
+
+ status = psa_driver_wrapper_verify_hash_start(operation, &attributes,
+ slot->key.data,
+ slot->key.bytes,
+ alg, hash, hash_length,
+ signature, signature_length);
+
+ if (status != PSA_SUCCESS) {
+ operation->error_occurred = 1;
+ psa_verify_hash_abort_internal(operation);
+ }
+
+ unlock_status = psa_unlock_key_slot(slot);
+
+ if (unlock_status != PSA_SUCCESS) {
+ operation->error_occurred = 1;
+ }
+
+ return (status == PSA_SUCCESS) ? unlock_status : status;
+}
+
+psa_status_t psa_verify_hash_complete(
+ psa_verify_hash_interruptible_operation_t *operation)
+{
+ psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+
+ /* Check that start has been called first, and that operation has not
+ * previously errored. */
+ if (operation->id == 0 || operation->error_occurred) {
+ status = PSA_ERROR_BAD_STATE;
+ goto exit;
+ }
+
+ status = psa_driver_wrapper_verify_hash_complete(operation);
+
+ /* Update ops count with work done. */
+ operation->num_ops = psa_driver_wrapper_verify_hash_get_num_ops(
+ operation);
+
+exit:
+
+ if (status != PSA_OPERATION_INCOMPLETE) {
+ if (status != PSA_SUCCESS) {
+ operation->error_occurred = 1;
+ }
+
+ psa_verify_hash_abort_internal(operation);
+ }
+
+ return status;
+}
+
+psa_status_t psa_verify_hash_abort(
+ psa_verify_hash_interruptible_operation_t *operation)
+{
+ psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+
+ status = psa_verify_hash_abort_internal(operation);
+
+ /* We clear the number of ops done here, so that it is not cleared when
+ * the operation fails or succeeds, only on manual abort. */
+ operation->num_ops = 0;
+
+ /* Likewise, failure state. */
+ operation->error_occurred = 0;
+
+ return status;
+}
+
+/****************************************************************/
+/* Asymmetric interruptible cryptography internal */
+/* implementations */
+/****************************************************************/
+
+static uint32_t mbedtls_psa_interruptible_max_ops =
+ PSA_INTERRUPTIBLE_MAX_OPS_UNLIMITED;
+
+void mbedtls_psa_interruptible_set_max_ops(uint32_t max_ops)
+{
+ mbedtls_psa_interruptible_max_ops = max_ops;
+
+#if (defined(MBEDTLS_PSA_BUILTIN_ALG_ECDSA) || \
+ defined(MBEDTLS_PSA_BUILTIN_ALG_DETERMINISTIC_ECDSA)) && \
+ defined(MBEDTLS_ECP_RESTARTABLE)
+
+ /* Internal implementation uses zero to indicate infinite number max ops,
+ * therefore avoid this value, and set to minimum possible. */
+ if (max_ops == 0) {
+ max_ops = 1;
+ }
+
+ mbedtls_ecp_set_max_ops(max_ops);
+#endif /* defined(MBEDTLS_PSA_BUILTIN_ALG_ECDSA) ||
+ * defined(MBEDTLS_PSA_BUILTIN_ALG_DETERMINISTIC_ECDSA) &&
+ * defined( MBEDTLS_ECP_RESTARTABLE ) */
+}
+
+uint32_t mbedtls_psa_interruptible_get_max_ops(void)
+{
+ return mbedtls_psa_interruptible_max_ops;
+}
+
+uint32_t mbedtls_psa_sign_hash_get_num_ops(
+ const mbedtls_psa_sign_hash_interruptible_operation_t *operation)
+{
+#if (defined(MBEDTLS_PSA_BUILTIN_ALG_ECDSA) || \
+ defined(MBEDTLS_PSA_BUILTIN_ALG_DETERMINISTIC_ECDSA)) && \
+ defined(MBEDTLS_ECP_RESTARTABLE)
+
+ return operation->num_ops;
+#else
+ (void) operation;
+ return 0;
+#endif /* defined(MBEDTLS_PSA_BUILTIN_ALG_ECDSA) ||
+ * defined(MBEDTLS_PSA_BUILTIN_ALG_DETERMINISTIC_ECDSA) &&
+ * defined( MBEDTLS_ECP_RESTARTABLE ) */
+}
+
+uint32_t mbedtls_psa_verify_hash_get_num_ops(
+ const mbedtls_psa_verify_hash_interruptible_operation_t *operation)
+{
+ #if (defined(MBEDTLS_PSA_BUILTIN_ALG_ECDSA) || \
+ defined(MBEDTLS_PSA_BUILTIN_ALG_DETERMINISTIC_ECDSA)) && \
+ defined(MBEDTLS_ECP_RESTARTABLE)
+
+ return operation->num_ops;
+#else
+ (void) operation;
+ return 0;
+#endif /* defined(MBEDTLS_PSA_BUILTIN_ALG_ECDSA) ||
+ * defined(MBEDTLS_PSA_BUILTIN_ALG_DETERMINISTIC_ECDSA) &&
+ * defined( MBEDTLS_ECP_RESTARTABLE ) */
+}
+
+psa_status_t mbedtls_psa_sign_hash_start(
+ mbedtls_psa_sign_hash_interruptible_operation_t *operation,
+ const psa_key_attributes_t *attributes, const uint8_t *key_buffer,
+ size_t key_buffer_size, psa_algorithm_t alg,
+ const uint8_t *hash, size_t hash_length)
+{
+ psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+ size_t required_hash_length;
+
+ if (!PSA_KEY_TYPE_IS_ECC(attributes->core.type)) {
+ return PSA_ERROR_NOT_SUPPORTED;
+ }
+
+ if (!PSA_ALG_IS_ECDSA(alg)) {
+ return PSA_ERROR_NOT_SUPPORTED;
+ }
+
+#if (defined(MBEDTLS_PSA_BUILTIN_ALG_ECDSA) || \
+ defined(MBEDTLS_PSA_BUILTIN_ALG_DETERMINISTIC_ECDSA)) && \
+ defined(MBEDTLS_ECP_RESTARTABLE)
+
+ mbedtls_ecdsa_restart_init(&operation->restart_ctx);
+
+ /* Ensure num_ops is zero'ed in case of context re-use. */
+ operation->num_ops = 0;
+
+ /* Ensure default is set even if
+ * mbedtls_psa_interruptible_set_max_ops() has not been called. */
+ mbedtls_psa_interruptible_set_max_ops(
+ mbedtls_psa_interruptible_get_max_ops());
+
+ status = mbedtls_psa_ecp_load_representation(attributes->core.type,
+ attributes->core.bits,
+ key_buffer,
+ key_buffer_size,
+ &operation->ctx);
+
+ if (status != PSA_SUCCESS) {
+ return status;
+ }
+
+ operation->coordinate_bytes = PSA_BITS_TO_BYTES(
+ operation->ctx->grp.nbits);
+
+ psa_algorithm_t hash_alg = PSA_ALG_SIGN_GET_HASH(alg);
+ operation->md_alg = mbedtls_hash_info_md_from_psa(hash_alg);
+ operation->alg = alg;
+
+ /* We only need to store the same length of hash as the private key size
+ * here, it would be truncated by the internal implementation anyway. */
+ required_hash_length = (hash_length < operation->coordinate_bytes ?
+ hash_length : operation->coordinate_bytes);
+
+ if (required_hash_length > sizeof(operation->hash)) {
+ /* Shouldn't happen, but better safe than sorry. */
+ return PSA_ERROR_CORRUPTION_DETECTED;
+ }
+
+ memcpy(operation->hash, hash, required_hash_length);
+ operation->hash_length = required_hash_length;
+
+ return PSA_SUCCESS;
+
+#else
+ (void) operation;
+ (void) key_buffer;
+ (void) key_buffer_size;
+ (void) alg;
+ (void) hash;
+ (void) hash_length;
+ (void) status;
+ (void) required_hash_length;
+
+ return PSA_ERROR_NOT_SUPPORTED;
+#endif /* defined(MBEDTLS_PSA_BUILTIN_ALG_ECDSA) ||
+ * defined(MBEDTLS_PSA_BUILTIN_ALG_DETERMINISTIC_ECDSA) &&
+ * defined( MBEDTLS_ECP_RESTARTABLE ) */
+}
+
+psa_status_t mbedtls_psa_sign_hash_complete(
+ mbedtls_psa_sign_hash_interruptible_operation_t *operation,
+ uint8_t *signature, size_t signature_size,
+ size_t *signature_length)
+{
+#if (defined(MBEDTLS_PSA_BUILTIN_ALG_ECDSA) || \
+ defined(MBEDTLS_PSA_BUILTIN_ALG_DETERMINISTIC_ECDSA)) && \
+ defined(MBEDTLS_ECP_RESTARTABLE)
+
+ psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+ mbedtls_mpi r;
+ mbedtls_mpi s;
+
+ mbedtls_mpi_init(&r);
+ mbedtls_mpi_init(&s);
+
+ if (signature_size < 2 * operation->coordinate_bytes) {
+ status = PSA_ERROR_BUFFER_TOO_SMALL;
+ goto exit;
+ }
+
+ if (PSA_ALG_ECDSA_IS_DETERMINISTIC(operation->alg)) {
+
+#if defined(MBEDTLS_PSA_BUILTIN_ALG_DETERMINISTIC_ECDSA)
+ status = mbedtls_to_psa_error(
+ mbedtls_ecdsa_sign_det_restartable(&operation->ctx->grp,
+ &r,
+ &s,
+ &operation->ctx->d,
+ operation->hash,
+ operation->hash_length,
+ operation->md_alg,
+ mbedtls_psa_get_random,
+ MBEDTLS_PSA_RANDOM_STATE,
+ &operation->restart_ctx));
+#else /* defined(MBEDTLS_PSA_BUILTIN_ALG_DETERMINISTIC_ECDSA) */
+ status = PSA_ERROR_NOT_SUPPORTED;
+ goto exit;
+#endif /* defined(MBEDTLS_PSA_BUILTIN_ALG_DETERMINISTIC_ECDSA) */
+ } else {
+ status = mbedtls_to_psa_error(
+ mbedtls_ecdsa_sign_restartable(&operation->ctx->grp,
+ &r,
+ &s,
+ &operation->ctx->d,
+ operation->hash,
+ operation->hash_length,
+ mbedtls_psa_get_random,
+ MBEDTLS_PSA_RANDOM_STATE,
+ mbedtls_psa_get_random,
+ MBEDTLS_PSA_RANDOM_STATE,
+ &operation->restart_ctx));
+ }
+
+ /* Hide the fact that the restart context only holds a delta of number of
+ * ops done during the last operation, not an absolute value. */
+ operation->num_ops += operation->restart_ctx.ecp.ops_done;
+
+ if (status == PSA_SUCCESS) {
+ status = mbedtls_to_psa_error(
+ mbedtls_mpi_write_binary(&r,
+ signature,
+ operation->coordinate_bytes)
+ );
+
+ if (status != PSA_SUCCESS) {
+ goto exit;
+ }
+
+ status = mbedtls_to_psa_error(
+ mbedtls_mpi_write_binary(&s,
+ signature +
+ operation->coordinate_bytes,
+ operation->coordinate_bytes)
+ );
+
+ if (status != PSA_SUCCESS) {
+ goto exit;
+ }
+
+ *signature_length = operation->coordinate_bytes * 2;
+
+ status = PSA_SUCCESS;
+ }
+
+exit:
+
+ mbedtls_mpi_free(&r);
+ mbedtls_mpi_free(&s);
+ return status;
+
+ #else
+
+ (void) operation;
+ (void) signature;
+ (void) signature_size;
+ (void) signature_length;
+
+ return PSA_ERROR_NOT_SUPPORTED;
+
+#endif /* defined(MBEDTLS_PSA_BUILTIN_ALG_ECDSA) ||
+ * defined(MBEDTLS_PSA_BUILTIN_ALG_DETERMINISTIC_ECDSA) &&
+ * defined( MBEDTLS_ECP_RESTARTABLE ) */
+}
+
+psa_status_t mbedtls_psa_sign_hash_abort(
+ mbedtls_psa_sign_hash_interruptible_operation_t *operation)
+{
+
+#if (defined(MBEDTLS_PSA_BUILTIN_ALG_ECDSA) || \
+ defined(MBEDTLS_PSA_BUILTIN_ALG_DETERMINISTIC_ECDSA)) && \
+ defined(MBEDTLS_ECP_RESTARTABLE)
+
+ if (operation->ctx) {
+ mbedtls_ecdsa_free(operation->ctx);
+ mbedtls_free(operation->ctx);
+ operation->ctx = NULL;
+ }
+
+ mbedtls_ecdsa_restart_free(&operation->restart_ctx);
+
+ operation->num_ops = 0;
+
+ return PSA_SUCCESS;
+
+#else
+
+ (void) operation;
+
+ return PSA_ERROR_NOT_SUPPORTED;
+
+#endif /* defined(MBEDTLS_PSA_BUILTIN_ALG_ECDSA) ||
+ * defined(MBEDTLS_PSA_BUILTIN_ALG_DETERMINISTIC_ECDSA) &&
+ * defined( MBEDTLS_ECP_RESTARTABLE ) */
+}
+
+psa_status_t mbedtls_psa_verify_hash_start(
+ mbedtls_psa_verify_hash_interruptible_operation_t *operation,
+ const psa_key_attributes_t *attributes,
+ const uint8_t *key_buffer, size_t key_buffer_size,
+ psa_algorithm_t alg,
+ const uint8_t *hash, size_t hash_length,
+ const uint8_t *signature, size_t signature_length)
+{
+ psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+ size_t coordinate_bytes = 0;
+ size_t required_hash_length = 0;
+
+ if (!PSA_KEY_TYPE_IS_ECC(attributes->core.type)) {
+ return PSA_ERROR_NOT_SUPPORTED;
+ }
+
+ if (!PSA_ALG_IS_ECDSA(alg)) {
+ return PSA_ERROR_NOT_SUPPORTED;
+ }
+
+#if (defined(MBEDTLS_PSA_BUILTIN_ALG_ECDSA) || \
+ defined(MBEDTLS_PSA_BUILTIN_ALG_DETERMINISTIC_ECDSA)) && \
+ defined(MBEDTLS_ECP_RESTARTABLE)
+
+ mbedtls_ecdsa_restart_init(&operation->restart_ctx);
+ mbedtls_mpi_init(&operation->r);
+ mbedtls_mpi_init(&operation->s);
+
+ /* Ensure num_ops is zero'ed in case of context re-use. */
+ operation->num_ops = 0;
+
+ /* Ensure default is set even if
+ * mbedtls_psa_interruptible_set_max_ops() has not been called. */
+ mbedtls_psa_interruptible_set_max_ops(
+ mbedtls_psa_interruptible_get_max_ops());
+
+ status = mbedtls_psa_ecp_load_representation(attributes->core.type,
+ attributes->core.bits,
+ key_buffer,
+ key_buffer_size,
+ &operation->ctx);
+
+ if (status != PSA_SUCCESS) {
+ return status;
+ }
+
+ coordinate_bytes = PSA_BITS_TO_BYTES(operation->ctx->grp.nbits);
+
+ if (signature_length != 2 * coordinate_bytes) {
+ return PSA_ERROR_INVALID_SIGNATURE;
+ }
+
+ status = mbedtls_to_psa_error(
+ mbedtls_mpi_read_binary(&operation->r,
+ signature,
+ coordinate_bytes));
+
+ if (status != PSA_SUCCESS) {
+ return status;
+ }
+
+ status = mbedtls_to_psa_error(
+ mbedtls_mpi_read_binary(&operation->s,
+ signature +
+ coordinate_bytes,
+ coordinate_bytes));
+
+ if (status != PSA_SUCCESS) {
+ return status;
+ }
+
+ status = mbedtls_psa_ecp_load_public_part(operation->ctx);
+
+ if (status != PSA_SUCCESS) {
+ return status;
+ }
+
+ /* We only need to store the same length of hash as the private key size
+ * here, it would be truncated by the internal implementation anyway. */
+ required_hash_length = (hash_length < coordinate_bytes ? hash_length :
+ coordinate_bytes);
+
+ if (required_hash_length > sizeof(operation->hash)) {
+ /* Shouldn't happen, but better safe than sorry. */
+ return PSA_ERROR_CORRUPTION_DETECTED;
+ }
+
+ memcpy(operation->hash, hash, required_hash_length);
+ operation->hash_length = required_hash_length;
+
+ return PSA_SUCCESS;
+#else
+ (void) operation;
+ (void) key_buffer;
+ (void) key_buffer_size;
+ (void) alg;
+ (void) hash;
+ (void) hash_length;
+ (void) signature;
+ (void) signature_length;
+ (void) status;
+ (void) coordinate_bytes;
+ (void) required_hash_length;
+
+ return PSA_ERROR_NOT_SUPPORTED;
+#endif /* defined(MBEDTLS_PSA_BUILTIN_ALG_ECDSA) ||
+ * defined(MBEDTLS_PSA_BUILTIN_ALG_DETERMINISTIC_ECDSA) &&
+ * defined( MBEDTLS_ECP_RESTARTABLE ) */
+}
+
+psa_status_t mbedtls_psa_verify_hash_complete(
+ mbedtls_psa_verify_hash_interruptible_operation_t *operation)
+{
+
+#if (defined(MBEDTLS_PSA_BUILTIN_ALG_ECDSA) || \
+ defined(MBEDTLS_PSA_BUILTIN_ALG_DETERMINISTIC_ECDSA)) && \
+ defined(MBEDTLS_ECP_RESTARTABLE)
+
+ psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+
+ status = mbedtls_to_psa_error(
+ mbedtls_ecdsa_verify_restartable(&operation->ctx->grp,
+ operation->hash,
+ operation->hash_length,
+ &operation->ctx->Q,
+ &operation->r,
+ &operation->s,
+ &operation->restart_ctx));
+
+ /* Hide the fact that the restart context only holds a delta of number of
+ * ops done during the last operation, not an absolute value. */
+ operation->num_ops += operation->restart_ctx.ecp.ops_done;
+
+ return status;
+#else
+ (void) operation;
+
+ return PSA_ERROR_NOT_SUPPORTED;
+
+#endif /* defined(MBEDTLS_PSA_BUILTIN_ALG_ECDSA) ||
+ * defined(MBEDTLS_PSA_BUILTIN_ALG_DETERMINISTIC_ECDSA) &&
+ * defined( MBEDTLS_ECP_RESTARTABLE ) */
+}
+
+psa_status_t mbedtls_psa_verify_hash_abort(
+ mbedtls_psa_verify_hash_interruptible_operation_t *operation)
+{
+
+#if (defined(MBEDTLS_PSA_BUILTIN_ALG_ECDSA) || \
+ defined(MBEDTLS_PSA_BUILTIN_ALG_DETERMINISTIC_ECDSA)) && \
+ defined(MBEDTLS_ECP_RESTARTABLE)
+
+ if (operation->ctx) {
+ mbedtls_ecdsa_free(operation->ctx);
+ mbedtls_free(operation->ctx);
+ operation->ctx = NULL;
+ }
+
+ mbedtls_ecdsa_restart_free(&operation->restart_ctx);
+
+ operation->num_ops = 0;
+
+ mbedtls_mpi_free(&operation->r);
+ mbedtls_mpi_free(&operation->s);
+
+ return PSA_SUCCESS;
+
+#else
+ (void) operation;
+
+ return PSA_ERROR_NOT_SUPPORTED;
+
+#endif /* defined(MBEDTLS_PSA_BUILTIN_ALG_ECDSA) ||
+ * defined(MBEDTLS_PSA_BUILTIN_ALG_DETERMINISTIC_ECDSA) &&
+ * defined( MBEDTLS_ECP_RESTARTABLE ) */
+}
/****************************************************************/
/* Symmetric cryptography */
diff --git a/library/psa_crypto_core.h b/library/psa_crypto_core.h
index 38e4bc5cc..b1817e2da 100644
--- a/library/psa_crypto_core.h
+++ b/library/psa_crypto_core.h
@@ -606,4 +606,272 @@ psa_status_t psa_key_agreement_raw_builtin(
size_t shared_secret_size,
size_t *shared_secret_length);
+/**
+ * \brief Set the maximum number of ops allowed to be executed by an
+ * interruptible function in a single call.
+ *
+ * \note The signature of this function is that of a PSA driver
+ * interruptible_set_max_ops entry point. This function behaves as an
+ * interruptible_set_max_ops entry point as defined in the PSA driver
+ * interface specification for transparent drivers.
+ *
+ * \param[in] max_ops The maximum number of ops to be executed in a
+ * single call, this can be a number from 0 to
+ * #PSA_INTERRUPTIBLE_MAX_OPS_UNLIMITED, where 0
+ * is obviously the least amount of work done per
+ * call.
+ */
+void mbedtls_psa_interruptible_set_max_ops(uint32_t max_ops);
+
+/**
+ * \brief Get the maximum number of ops allowed to be executed by an
+ * interruptible function in a single call.
+ *
+ * \note The signature of this function is that of a PSA driver
+ * interruptible_get_max_ops entry point. This function behaves as an
+ * interruptible_get_max_ops entry point as defined in the PSA driver
+ * interface specification for transparent drivers.
+ *
+ * \return Maximum number of ops allowed to be executed
+ * by an interruptible function in a single call.
+ */
+uint32_t mbedtls_psa_interruptible_get_max_ops(void);
+
+/**
+ * \brief Get the number of ops that a hash signing operation has taken for the
+ * previous call. If no call or work has taken place, this will return
+ * zero.
+ *
+ * \note The signature of this function is that of a PSA driver
+ * sign_hash_get_num_ops entry point. This function behaves as an
+ * sign_hash_get_num_ops entry point as defined in the PSA driver
+ * interface specification for transparent drivers.
+ *
+ * \param operation The \c
+ * mbedtls_psa_sign_hash_interruptible_operation_t
+ * to use. This must be initialized first.
+ *
+ * \return Number of ops that were completed
+ * in the last call to \c
+ * mbedtls_psa_sign_hash_complete().
+ */
+uint32_t mbedtls_psa_sign_hash_get_num_ops(
+ const mbedtls_psa_sign_hash_interruptible_operation_t *operation);
+
+/**
+ * \brief Get the number of ops that a hash verification operation has taken for
+ * the previous call. If no call or work has taken place, this will
+ * return zero.
+ *
+ * \note The signature of this function is that of a PSA driver
+ * verify_hash_get_num_ops entry point. This function behaves as an
+ * verify_hash_get_num_ops entry point as defined in the PSA driver
+ * interface specification for transparent drivers.
+ *
+ * \param operation The \c
+ * mbedtls_psa_verify_hash_interruptible_operation_t
+ * to use. This must be initialized first.
+ *
+ * \return Number of ops that were completed
+ * in the last call to \c
+ * mbedtls_psa_verify_hash_complete().
+ */
+uint32_t mbedtls_psa_verify_hash_get_num_ops(
+ const mbedtls_psa_verify_hash_interruptible_operation_t *operation);
+
+/**
+ * \brief Start signing a hash or short message with a private key, in an
+ * interruptible manner.
+ *
+ * \note The signature of this function is that of a PSA driver
+ * sign_hash_start entry point. This function behaves as a
+ * sign_hash_start entry point as defined in the PSA driver interface
+ * specification for transparent drivers.
+ *
+ * \param[in] operation The \c
+ * mbedtls_psa_sign_hash_interruptible_operation_t
+ * to use. This must be initialized first.
+ * \param[in] attributes The attributes of the key to use for the
+ * operation.
+ * \param[in] key_buffer The buffer containing the key context.
+ * \param[in] key_buffer_size Size of the \p key_buffer buffer in bytes.
+ * \param[in] alg A signature algorithm that is compatible with
+ * the type of the key.
+ * \param[in] hash The hash or message to sign.
+ * \param hash_length Size of the \p hash buffer in bytes.
+ *
+ * \retval #PSA_SUCCESS
+ * The operation started successfully - call \c psa_sign_hash_complete()
+ * with the same context to complete the operation
+ * \retval #PSA_ERROR_INVALID_ARGUMENT
+ * An unsupported, incorrectly formatted or incorrect type of key was
+ * used.
+ * \retval #PSA_ERROR_NOT_SUPPORTED Either no internal interruptible operations
+ * are currently supported, or the key type is currently unsupported.
+ * \retval #PSA_ERROR_INSUFFICIENT_MEMORY
+ * There was insufficient memory to load the key representation.
+ */
+psa_status_t mbedtls_psa_sign_hash_start(
+ mbedtls_psa_sign_hash_interruptible_operation_t *operation,
+ const psa_key_attributes_t *attributes, const uint8_t *key_buffer,
+ size_t key_buffer_size, psa_algorithm_t alg,
+ const uint8_t *hash, size_t hash_length);
+
+/**
+ * \brief Continue and eventually complete the action of signing a hash or
+ * short message with a private key, in an interruptible manner.
+ *
+ * \note The signature of this function is that of a PSA driver
+ * sign_hash_complete entry point. This function behaves as a
+ * sign_hash_complete entry point as defined in the PSA driver interface
+ * specification for transparent drivers.
+ *
+ * \param[in] operation The \c
+ * mbedtls_psa_sign_hash_interruptible_operation_t
+ * to use. This must be initialized first.
+ *
+ * \param[out] signature Buffer where the signature is to be written.
+ * \param signature_size Size of the \p signature buffer in bytes. This
+ * must be appropriate for the selected
+ * algorithm and key.
+ * \param[out] signature_length On success, the number of bytes that make up
+ * the returned signature value.
+ *
+ * \retval #PSA_SUCCESS
+ * Operation completed successfully
+ *
+ * \retval #PSA_OPERATION_INCOMPLETE
+ * Operation was interrupted due to the setting of \c
+ * psa_interruptible_set_max_ops(), there is still work to be done,
+ * please call this function again with the same operation object.
+ *
+ * \retval #PSA_ERROR_BUFFER_TOO_SMALL
+ * The size of the \p signature buffer is too small. You can
+ * determine a sufficient buffer size by calling
+ * #PSA_SIGN_OUTPUT_SIZE(\c key_type, \c key_bits, \p alg)
+ * where \c key_type and \c key_bits are the type and bit-size
+ * respectively of \p key.
+ *
+ * \retval #PSA_ERROR_NOT_SUPPORTED
+ * \retval #PSA_ERROR_INVALID_ARGUMENT
+ * \retval #PSA_ERROR_INSUFFICIENT_MEMORY
+ * \retval #PSA_ERROR_CORRUPTION_DETECTED
+ * \retval #PSA_ERROR_INSUFFICIENT_ENTROPY
+ */
+psa_status_t mbedtls_psa_sign_hash_complete(
+ mbedtls_psa_sign_hash_interruptible_operation_t *operation,
+ uint8_t *signature, size_t signature_size,
+ size_t *signature_length);
+
+/**
+ * \brief Abort a sign hash operation.
+ *
+ * \note The signature of this function is that of a PSA driver sign_hash_abort
+ * entry point. This function behaves as a sign_hash_abort entry point as
+ * defined in the PSA driver interface specification for transparent
+ * drivers.
+ *
+ * \param[in] operation The \c
+ * mbedtls_psa_sign_hash_interruptible_operation_t
+ * to abort.
+ *
+ * \retval #PSA_SUCCESS
+ * The operation was aborted successfully.
+ */
+psa_status_t mbedtls_psa_sign_hash_abort(
+ mbedtls_psa_sign_hash_interruptible_operation_t *operation);
+
+/**
+ * \brief Start reading and verifying a hash or short message, in an
+ * interruptible manner.
+ *
+ * \note The signature of this function is that of a PSA driver
+ * verify_hash_start entry point. This function behaves as a
+ * verify_hash_start entry point as defined in the PSA driver interface
+ * specification for transparent drivers.
+ *
+ * \param[in] operation The \c
+ * mbedtls_psa_verify_hash_interruptible_operation_t
+ * to use. This must be initialized first.
+ * \param[in] attributes The attributes of the key to use for the
+ * operation.
+ * \param[in] key_buffer The buffer containing the key context.
+ * \param[in] key_buffer_size Size of the \p key_buffer buffer in bytes.
+ * \param[in] alg A signature algorithm that is compatible with
+ * the type of the key.
+ * \param[in] hash The hash whose signature is to be verified.
+ * \param hash_length Size of the \p hash buffer in bytes.
+ * \param[in] signature Buffer containing the signature to verify.
+ * \param signature_length Size of the \p signature buffer in bytes.
+ *
+ * \retval #PSA_SUCCESS
+ * The operation started successfully - call \c psa_sign_hash_complete()
+ * with the same context to complete the operation
+ * \retval #PSA_ERROR_INVALID_ARGUMENT
+ * An unsupported or incorrect type of key was used.
+ * \retval #PSA_ERROR_NOT_SUPPORTED
+ * Either no internal interruptible operations are currently supported,
+ * or the key type is currently unsupported.
+ * \retval #PSA_ERROR_INSUFFICIENT_MEMORY
+ * There was insufficient memory either to load the key representation,
+ * or to prepare the operation.
+ */
+psa_status_t mbedtls_psa_verify_hash_start(
+ mbedtls_psa_verify_hash_interruptible_operation_t *operation,
+ const psa_key_attributes_t *attributes,
+ const uint8_t *key_buffer, size_t key_buffer_size,
+ psa_algorithm_t alg,
+ const uint8_t *hash, size_t hash_length,
+ const uint8_t *signature, size_t signature_length);
+
+/**
+ * \brief Continue and eventually complete the action of signing a hash or
+ * short message with a private key, in an interruptible manner.
+ *
+ * \note The signature of this function is that of a PSA driver
+ * sign_hash_complete entry point. This function behaves as a
+ * sign_hash_complete entry point as defined in the PSA driver interface
+ * specification for transparent drivers.
+ *
+ * \param[in] operation The \c
+ * mbedtls_psa_sign_hash_interruptible_operation_t
+ * to use. This must be initialized first.
+ *
+ * \retval #PSA_SUCCESS
+ * Operation completed successfully, and the passed signature is valid.
+ *
+ * \retval #PSA_OPERATION_INCOMPLETE
+ * Operation was interrupted due to the setting of \c
+ * psa_interruptible_set_max_ops(), there is still work to be done,
+ * please call this function again with the same operation object.
+ *
+ * \retval #PSA_ERROR_INVALID_SIGNATURE
+ * The calculation was performed successfully, but the passed
+ * signature is not a valid signature.
+ *
+ * \retval #PSA_ERROR_NOT_SUPPORTED
+ * \retval #PSA_ERROR_INVALID_ARGUMENT
+ * \retval #PSA_ERROR_INSUFFICIENT_MEMORY
+ */
+psa_status_t mbedtls_psa_verify_hash_complete(
+ mbedtls_psa_verify_hash_interruptible_operation_t *operation);
+
+/**
+ * \brief Abort a verify signed hash operation.
+ *
+ * \note The signature of this function is that of a PSA driver
+ * verify_hash_abort entry point. This function behaves as a
+ * verify_hash_abort entry point as defined in the PSA driver interface
+ * specification for transparent drivers.
+ *
+ * \param[in] operation The \c
+ * mbedtls_psa_verify_hash_interruptible_operation_t
+ * to abort.
+ *
+ * \retval #PSA_SUCCESS
+ * The operation was aborted successfully.
+ */
+psa_status_t mbedtls_psa_verify_hash_abort(
+ mbedtls_psa_verify_hash_interruptible_operation_t *operation);
+
#endif /* PSA_CRYPTO_CORE_H */
diff --git a/library/psa_crypto_driver_wrappers.h b/library/psa_crypto_driver_wrappers.h
index da3cd1d5d..e3edec791 100644
--- a/library/psa_crypto_driver_wrappers.h
+++ b/library/psa_crypto_driver_wrappers.h
@@ -66,6 +66,47 @@ psa_status_t psa_driver_wrapper_verify_hash(
psa_algorithm_t alg, const uint8_t *hash, size_t hash_length,
const uint8_t *signature, size_t signature_length);
+/*
+ * Interruptible Signature functions
+ */
+
+void psa_driver_wrapper_interruptible_set_max_ops(uint32_t max_ops);
+
+uint32_t psa_driver_wrapper_interruptible_get_max_ops(void);
+
+uint32_t psa_driver_wrapper_sign_hash_get_num_ops(
+ psa_sign_hash_interruptible_operation_t *operation);
+
+uint32_t psa_driver_wrapper_verify_hash_get_num_ops(
+ psa_verify_hash_interruptible_operation_t *operation);
+
+psa_status_t psa_driver_wrapper_sign_hash_start(
+ psa_sign_hash_interruptible_operation_t *operation,
+ const psa_key_attributes_t *attributes, const uint8_t *key_buffer,
+ size_t key_buffer_size, psa_algorithm_t alg,
+ const uint8_t *hash, size_t hash_length);
+
+psa_status_t psa_driver_wrapper_sign_hash_complete(
+ psa_sign_hash_interruptible_operation_t *operation,
+ uint8_t *signature, size_t signature_size,
+ size_t *signature_length);
+
+psa_status_t psa_driver_wrapper_sign_hash_abort(
+ psa_sign_hash_interruptible_operation_t *operation);
+
+psa_status_t psa_driver_wrapper_verify_hash_start(
+ psa_verify_hash_interruptible_operation_t *operation,
+ const psa_key_attributes_t *attributes, const uint8_t *key_buffer,
+ size_t key_buffer_size, psa_algorithm_t alg,
+ const uint8_t *hash, size_t hash_length,
+ const uint8_t *signature, size_t signature_length);
+
+psa_status_t psa_driver_wrapper_verify_hash_complete(
+ psa_verify_hash_interruptible_operation_t *operation);
+
+psa_status_t psa_driver_wrapper_verify_hash_abort(
+ psa_verify_hash_interruptible_operation_t *operation);
+
/*
* Key handling functions
*/
diff --git a/library/psa_crypto_ecp.c b/library/psa_crypto_ecp.c
index c4ccefd75..f70d804b0 100644
--- a/library/psa_crypto_ecp.c
+++ b/library/psa_crypto_ecp.c
@@ -404,6 +404,21 @@ cleanup:
return mbedtls_to_psa_error(ret);
}
+psa_status_t mbedtls_psa_ecp_load_public_part(mbedtls_ecp_keypair *ecp)
+{
+ int ret = 0;
+
+ /* Check whether the public part is loaded. If not, load it. */
+ if (mbedtls_ecp_is_zero(&ecp->Q)) {
+ ret = mbedtls_ecp_mul(&ecp->grp, &ecp->Q,
+ &ecp->d, &ecp->grp.G,
+ mbedtls_psa_get_random,
+ MBEDTLS_PSA_RANDOM_STATE);
+ }
+
+ return mbedtls_to_psa_error(ret);
+}
+
psa_status_t mbedtls_psa_ecdsa_verify_hash(
const psa_key_attributes_t *attributes,
const uint8_t *key_buffer, size_t key_buffer_size,
@@ -412,7 +427,6 @@ psa_status_t mbedtls_psa_ecdsa_verify_hash(
{
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
mbedtls_ecp_keypair *ecp = NULL;
- int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
size_t curve_bytes;
mbedtls_mpi r, s;
@@ -432,34 +446,39 @@ psa_status_t mbedtls_psa_ecdsa_verify_hash(
mbedtls_mpi_init(&s);
if (signature_length != 2 * curve_bytes) {
- ret = MBEDTLS_ERR_ECP_VERIFY_FAILED;
+ status = PSA_ERROR_INVALID_SIGNATURE;
goto cleanup;
}
- MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&r,
- signature,
- curve_bytes));
- MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&s,
- signature + curve_bytes,
- curve_bytes));
-
- /* Check whether the public part is loaded. If not, load it. */
- if (mbedtls_ecp_is_zero(&ecp->Q)) {
- MBEDTLS_MPI_CHK(
- mbedtls_ecp_mul(&ecp->grp, &ecp->Q, &ecp->d, &ecp->grp.G,
- mbedtls_psa_get_random, MBEDTLS_PSA_RANDOM_STATE));
+ status = mbedtls_to_psa_error(mbedtls_mpi_read_binary(&r,
+ signature,
+ curve_bytes));
+ if (status != PSA_SUCCESS) {
+ goto cleanup;
}
- ret = mbedtls_ecdsa_verify(&ecp->grp, hash, hash_length,
- &ecp->Q, &r, &s);
+ status = mbedtls_to_psa_error(mbedtls_mpi_read_binary(&s,
+ signature + curve_bytes,
+ curve_bytes));
+ if (status != PSA_SUCCESS) {
+ goto cleanup;
+ }
+ status = mbedtls_psa_ecp_load_public_part(ecp);
+ if (status != PSA_SUCCESS) {
+ goto cleanup;
+ }
+
+ status = mbedtls_to_psa_error(mbedtls_ecdsa_verify(&ecp->grp, hash,
+ hash_length, &ecp->Q,
+ &r, &s));
cleanup:
mbedtls_mpi_free(&r);
mbedtls_mpi_free(&s);
mbedtls_ecp_keypair_free(ecp);
mbedtls_free(ecp);
- return mbedtls_to_psa_error(ret);
+ return status;
}
#endif /* defined(MBEDTLS_PSA_BUILTIN_ALG_ECDSA) || \
diff --git a/library/psa_crypto_ecp.h b/library/psa_crypto_ecp.h
index 71f9d6acc..c7ef534b1 100644
--- a/library/psa_crypto_ecp.h
+++ b/library/psa_crypto_ecp.h
@@ -48,6 +48,15 @@ psa_status_t mbedtls_psa_ecp_load_representation(psa_key_type_t type,
size_t data_length,
mbedtls_ecp_keypair **p_ecp);
+/** Load the public part of an internal ECP, if required.
+ *
+ * \param ecp The ECP context to load the public part for.
+ *
+ * \return PSA_SUCCESS on success, otherwise an MPI error.
+ */
+
+psa_status_t mbedtls_psa_ecp_load_public_part(mbedtls_ecp_keypair *ecp);
+
/** Import an ECP key in binary format.
*
* \note The signature of this function is that of a PSA driver
diff --git a/scripts/data_files/driver_templates/psa_crypto_driver_wrappers.c.jinja b/scripts/data_files/driver_templates/psa_crypto_driver_wrappers.c.jinja
index bdf331516..b35e726a0 100644
--- a/scripts/data_files/driver_templates/psa_crypto_driver_wrappers.c.jinja
+++ b/scripts/data_files/driver_templates/psa_crypto_driver_wrappers.c.jinja
@@ -433,6 +433,269 @@ psa_status_t psa_driver_wrapper_verify_hash(
}
}
+void psa_driver_wrapper_interruptible_set_max_ops( uint32_t max_ops )
+{
+ /* TODO - dispatch to drivers dynamically registered for this
+ * service when registering is implemented. For now, fall
+ * through to internal implementation. */
+
+ mbedtls_psa_interruptible_set_max_ops( max_ops );
+}
+
+uint32_t psa_driver_wrapper_interruptible_get_max_ops( void )
+{
+ /* TODO - dispatch to drivers dynamically registered for this
+ * service when registering is implemented. For now, fall
+ * through to internal implementation. */
+
+ return mbedtls_psa_interruptible_get_max_ops( );
+}
+
+uint32_t psa_driver_wrapper_sign_hash_get_num_ops(
+ psa_sign_hash_interruptible_operation_t *operation )
+{
+ switch( operation->id )
+ {
+ /* If uninitialised, return 0, as no work can have been done. */
+ case 0:
+ return 0;
+
+ case PSA_CRYPTO_MBED_TLS_DRIVER_ID:
+ return(mbedtls_psa_sign_hash_get_num_ops(&operation->ctx.mbedtls_ctx));
+
+#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT)
+#if defined(PSA_CRYPTO_DRIVER_TEST)
+ /* Add test driver tests here */
+
+#endif /* PSA_CRYPTO_DRIVER_TEST */
+#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */
+ }
+
+ return( PSA_ERROR_INVALID_ARGUMENT );
+}
+
+uint32_t psa_driver_wrapper_verify_hash_get_num_ops(
+ psa_verify_hash_interruptible_operation_t *operation )
+{
+ switch( operation->id )
+ {
+ /* If uninitialised, return 0, as no work can have been done. */
+ case 0:
+ return 0;
+
+ case PSA_CRYPTO_MBED_TLS_DRIVER_ID:
+ return (mbedtls_psa_verify_hash_get_num_ops(&operation->ctx.mbedtls_ctx));
+
+#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT)
+#if defined(PSA_CRYPTO_DRIVER_TEST)
+ /* Add test driver tests here */
+
+#endif /* PSA_CRYPTO_DRIVER_TEST */
+#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */
+
+ }
+
+ return( PSA_ERROR_INVALID_ARGUMENT );
+}
+
+psa_status_t psa_driver_wrapper_sign_hash_start(
+ psa_sign_hash_interruptible_operation_t *operation,
+ const psa_key_attributes_t *attributes, const uint8_t *key_buffer,
+ size_t key_buffer_size, psa_algorithm_t alg,
+ const uint8_t *hash, size_t hash_length )
+{
+ psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+ psa_key_location_t location =
+ PSA_KEY_LIFETIME_GET_LOCATION(
+ attributes->core.lifetime );
+
+ switch( location )
+ {
+ case PSA_KEY_LOCATION_LOCAL_STORAGE:
+ /* Key is stored in the slot in export representation, so
+ * cycle through all known transparent accelerators */
+
+#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT)
+#if defined(PSA_CRYPTO_DRIVER_TEST)
+
+ /* Add test driver tests here */
+
+ /* Declared with fallback == true */
+
+#endif /* PSA_CRYPTO_DRIVER_TEST */
+#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */
+
+ /* Fell through, meaning no accelerator supports this operation */
+ operation->id = PSA_CRYPTO_MBED_TLS_DRIVER_ID;
+ return( mbedtls_psa_sign_hash_start( &operation->ctx.mbedtls_ctx,
+ attributes,
+ key_buffer, key_buffer_size,
+ alg, hash, hash_length ) );
+ break;
+
+ /* Add cases for opaque driver here */
+
+ default:
+ /* Key is declared with a lifetime not known to us */
+ ( void ) status;
+ return( PSA_ERROR_INVALID_ARGUMENT );
+ }
+
+ ( void ) operation;
+ ( void ) key_buffer;
+ ( void ) key_buffer_size;
+ ( void ) alg;
+ ( void ) hash;
+ ( void ) hash_length;
+
+ return( status );
+}
+
+psa_status_t psa_driver_wrapper_sign_hash_complete(
+ psa_sign_hash_interruptible_operation_t *operation,
+ uint8_t *signature, size_t signature_size,
+ size_t *signature_length )
+{
+ switch( operation->id )
+ {
+ case PSA_CRYPTO_MBED_TLS_DRIVER_ID:
+ return( mbedtls_psa_sign_hash_complete( &operation->ctx.mbedtls_ctx,
+ signature, signature_size,
+ signature_length ) );
+
+#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT)
+#if defined(PSA_CRYPTO_DRIVER_TEST)
+ /* Add test driver tests here */
+
+#endif /* PSA_CRYPTO_DRIVER_TEST */
+#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */
+ }
+
+ ( void ) signature;
+ ( void ) signature_size;
+ ( void ) signature_length;
+
+ return( PSA_ERROR_INVALID_ARGUMENT );
+}
+
+psa_status_t psa_driver_wrapper_sign_hash_abort(
+ psa_sign_hash_interruptible_operation_t *operation )
+{
+ switch( operation->id )
+ {
+ case PSA_CRYPTO_MBED_TLS_DRIVER_ID:
+ return( mbedtls_psa_sign_hash_abort( &operation->ctx.mbedtls_ctx ) );
+
+#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT)
+#if defined(PSA_CRYPTO_DRIVER_TEST)
+ /* Add test driver tests here */
+
+#endif /* PSA_CRYPTO_DRIVER_TEST */
+#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */
+ }
+
+ return( PSA_ERROR_INVALID_ARGUMENT );
+}
+
+psa_status_t psa_driver_wrapper_verify_hash_start(
+ psa_verify_hash_interruptible_operation_t *operation,
+ const psa_key_attributes_t *attributes, const uint8_t *key_buffer,
+ size_t key_buffer_size, psa_algorithm_t alg,
+ const uint8_t *hash, size_t hash_length,
+ const uint8_t *signature, size_t signature_length )
+{
+
+ psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+ psa_key_location_t location = PSA_KEY_LIFETIME_GET_LOCATION(
+ attributes->core.lifetime );
+
+ switch( location )
+ {
+ case PSA_KEY_LOCATION_LOCAL_STORAGE:
+ /* Key is stored in the slot in export representation, so
+ * cycle through all known transparent accelerators */
+
+#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT)
+#if defined(PSA_CRYPTO_DRIVER_TEST)
+
+ /* Add test driver tests here */
+
+ /* Declared with fallback == true */
+
+#endif /* PSA_CRYPTO_DRIVER_TEST */
+#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */
+
+ /* Fell through, meaning no accelerator supports this operation */
+ operation->id = PSA_CRYPTO_MBED_TLS_DRIVER_ID;
+ return( mbedtls_psa_verify_hash_start( &operation->ctx.mbedtls_ctx,
+ attributes,
+ key_buffer, key_buffer_size,
+ alg, hash, hash_length,
+ signature, signature_length
+ ) );
+ break;
+
+ /* Add cases for opaque driver here */
+
+ default:
+ /* Key is declared with a lifetime not known to us */
+ ( void ) status;
+ return( PSA_ERROR_INVALID_ARGUMENT );
+ }
+
+ ( void ) operation;
+ ( void ) key_buffer;
+ ( void ) key_buffer_size;
+ ( void ) alg;
+ ( void ) hash;
+ ( void ) hash_length;
+ ( void ) signature;
+ ( void ) signature_length;
+
+ return( status );
+}
+
+psa_status_t psa_driver_wrapper_verify_hash_complete(
+ psa_verify_hash_interruptible_operation_t *operation )
+{
+ switch( operation->id )
+ {
+ case PSA_CRYPTO_MBED_TLS_DRIVER_ID:
+ return( mbedtls_psa_verify_hash_complete(
+ &operation->ctx.mbedtls_ctx
+ ) );
+
+#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT)
+#if defined(PSA_CRYPTO_DRIVER_TEST)
+ /* Add test driver tests here */
+
+#endif /* PSA_CRYPTO_DRIVER_TEST */
+#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */
+ }
+
+ return( PSA_ERROR_INVALID_ARGUMENT );
+}
+
+psa_status_t psa_driver_wrapper_verify_hash_abort(
+ psa_verify_hash_interruptible_operation_t *operation )
+{
+ switch( operation->id )
+ {
+ case PSA_CRYPTO_MBED_TLS_DRIVER_ID:
+ return( mbedtls_psa_verify_hash_abort( &operation->ctx.mbedtls_ctx
+ ) );
+
+#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT)
+#if defined(PSA_CRYPTO_DRIVER_TEST)
+ /* Add test driver tests here */
+
+#endif /* PSA_CRYPTO_DRIVER_TEST */
+#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */
+ }
+
+ return( PSA_ERROR_INVALID_ARGUMENT );
+}
+
/** Calculate the key buffer size required to store the key material of a key
* associated with an opaque driver from input key data.
*
diff --git a/tests/suites/test_suite_psa_crypto.data b/tests/suites/test_suite_psa_crypto.data
index c3561420b..697cdd7b7 100644
--- a/tests/suites/test_suite_psa_crypto.data
+++ b/tests/suites/test_suite_psa_crypto.data
@@ -4145,6 +4145,30 @@ PSA sign hash: deterministic ECDSA SECP384R1 SHA-256
depends_on:PSA_WANT_ALG_DETERMINISTIC_ECDSA:PSA_WANT_ALG_SHA_256:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:MBEDTLS_PK_PARSE_C:PSA_WANT_ECC_SECP_R1_384
sign_hash_deterministic:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1):"3f5d8d9be280b5696cc5cc9f94cf8af7e6b61dd6592b2ab2b3a4c607450417ec327dcdcaed7c10053d719a0574f0a76a":PSA_ALG_DETERMINISTIC_ECDSA( PSA_ALG_SHA_256 ):"2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824":"52d92aac1fcc0fea3ecce01a9ed4bc9ac342f92470fd3f54d0d6d2fa5d2940405057a9d49a817c2b193322f05fc93ac1c7a055edac93bec0ade6814ab27b86b5295ac1ddb323818200f00c3d94d959f714f128b64a2e19628037ac009b14774f"
+PSA sign hash int (ops=inf): det ECDSA SECP256R1 SHA-256
+depends_on:PSA_WANT_ALG_DETERMINISTIC_ECDSA:PSA_WANT_ALG_SHA_256:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:MBEDTLS_PK_PARSE_C:PSA_WANT_ECC_SECP_R1_256
+sign_hash_interruptible:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1):"ab45435712649cb30bbddac49197eebf2740ffc7f874d9244c3460f54f322d3a":PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_256):"9ac4335b469bbd791439248504dd0d49c71349a295fee5a1c68507f45a9e1c7b":"6a3399f69421ffe1490377adf2ea1f117d81a63cf5bf22e918d51175eb259151ce95d7c26cc04e25503e2f7a1ec3573e3c2412534bb4a19b3a7811742f49f50f":PSA_INTERRUPTIBLE_MAX_OPS_UNLIMITED
+
+PSA sign hash int (ops=min): det ECDSA SECP256R1 SHA-256
+depends_on:PSA_WANT_ALG_DETERMINISTIC_ECDSA:PSA_WANT_ALG_SHA_256:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:MBEDTLS_PK_PARSE_C:PSA_WANT_ECC_SECP_R1_256
+sign_hash_interruptible:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1):"ab45435712649cb30bbddac49197eebf2740ffc7f874d9244c3460f54f322d3a":PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_256):"9ac4335b469bbd791439248504dd0d49c71349a295fee5a1c68507f45a9e1c7b":"6a3399f69421ffe1490377adf2ea1f117d81a63cf5bf22e918d51175eb259151ce95d7c26cc04e25503e2f7a1ec3573e3c2412534bb4a19b3a7811742f49f50f":1
+
+PSA sign hash int (ops=inf) det ECDSA SECP256R1 SHA-384
+depends_on:PSA_WANT_ALG_DETERMINISTIC_ECDSA:PSA_WANT_ALG_SHA_384:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:MBEDTLS_PK_PARSE_C:PSA_WANT_ECC_SECP_R1_256:MBEDTLS_PSA_BUILTIN_ALG_SHA_384
+sign_hash_interruptible:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1):"49c9a8c18c4b885638c431cf1df1c994131609b580d4fd43a0cab17db2f13eee":PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_384):"59e1748777448c69de6b800d7a33bbfb9ff1b463e44354c3553bcdb9c666fa90125a3c79f90397bdf5f6a13de828684f":"cd40ba1b555ca5994d30ddffc4ad734b1f5c604675b0f249814aa5de3992ef3ddf4d5dc5d2aab1979ce210b560754df671363d99795475882894c048e3b986ca":PSA_INTERRUPTIBLE_MAX_OPS_UNLIMITED
+
+PSA sign hash int (ops=min): det ECDSA SECP256R1 SHA-384
+depends_on:PSA_WANT_ALG_DETERMINISTIC_ECDSA:PSA_WANT_ALG_SHA_384:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:MBEDTLS_PK_PARSE_C:PSA_WANT_ECC_SECP_R1_256:MBEDTLS_PSA_BUILTIN_ALG_SHA_384
+sign_hash_interruptible:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1):"49c9a8c18c4b885638c431cf1df1c994131609b580d4fd43a0cab17db2f13eee":PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_384):"59e1748777448c69de6b800d7a33bbfb9ff1b463e44354c3553bcdb9c666fa90125a3c79f90397bdf5f6a13de828684f":"cd40ba1b555ca5994d30ddffc4ad734b1f5c604675b0f249814aa5de3992ef3ddf4d5dc5d2aab1979ce210b560754df671363d99795475882894c048e3b986ca":1
+
+PSA sign hash int (ops=inf): det ECDSA SECP384R1 SHA-256
+depends_on:PSA_WANT_ALG_DETERMINISTIC_ECDSA:PSA_WANT_ALG_SHA_256:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:MBEDTLS_PK_PARSE_C:PSA_WANT_ECC_SECP_R1_384
+sign_hash_interruptible:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1):"3f5d8d9be280b5696cc5cc9f94cf8af7e6b61dd6592b2ab2b3a4c607450417ec327dcdcaed7c10053d719a0574f0a76a":PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_256):"2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824":"52d92aac1fcc0fea3ecce01a9ed4bc9ac342f92470fd3f54d0d6d2fa5d2940405057a9d49a817c2b193322f05fc93ac1c7a055edac93bec0ade6814ab27b86b5295ac1ddb323818200f00c3d94d959f714f128b64a2e19628037ac009b14774f":PSA_INTERRUPTIBLE_MAX_OPS_UNLIMITED
+
+PSA sign hash int (ops=min): det ECDSA SECP384R1 SHA-256
+depends_on:PSA_WANT_ALG_DETERMINISTIC_ECDSA:PSA_WANT_ALG_SHA_256:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:MBEDTLS_PK_PARSE_C:PSA_WANT_ECC_SECP_R1_384
+sign_hash_interruptible:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1):"3f5d8d9be280b5696cc5cc9f94cf8af7e6b61dd6592b2ab2b3a4c607450417ec327dcdcaed7c10053d719a0574f0a76a":PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_256):"2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824":"52d92aac1fcc0fea3ecce01a9ed4bc9ac342f92470fd3f54d0d6d2fa5d2940405057a9d49a817c2b193322f05fc93ac1c7a055edac93bec0ade6814ab27b86b5295ac1ddb323818200f00c3d94d959f714f128b64a2e19628037ac009b14774f":1
+
PSA sign hash: RSA PKCS#1 v1.5 SHA-256, wrong hash size
depends_on:PSA_WANT_ALG_RSA_PKCS1V15_SIGN:PSA_WANT_ALG_SHA_256:PSA_WANT_KEY_TYPE_RSA_KEY_PAIR:MBEDTLS_PK_PARSE_C
sign_hash_fail:PSA_KEY_TYPE_RSA_KEY_PAIR:"3082025e02010002818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc3020301000102818100874bf0ffc2f2a71d14671ddd0171c954d7fdbf50281e4f6d99ea0e1ebcf82faa58e7b595ffb293d1abe17f110b37c48cc0f36c37e84d876621d327f64bbe08457d3ec4098ba2fa0a319fba411c2841ed7be83196a8cdf9daa5d00694bc335fc4c32217fe0488bce9cb7202e59468b1ead119000477db2ca797fac19eda3f58c1024100e2ab760841bb9d30a81d222de1eb7381d82214407f1b975cbbfe4e1a9467fd98adbd78f607836ca5be1928b9d160d97fd45c12d6b52e2c9871a174c66b488113024100c5ab27602159ae7d6f20c3c2ee851e46dc112e689e28d5fcbbf990a99ef8a90b8bb44fd36467e7fc1789ceb663abda338652c3c73f111774902e840565927091024100b6cdbd354f7df579a63b48b3643e353b84898777b48b15f94e0bfc0567a6ae5911d57ad6409cf7647bf96264e9bd87eb95e263b7110b9a1f9f94acced0fafa4d024071195eec37e8d257decfc672b07ae639f10cbb9b0c739d0c809968d644a94e3fd6ed9287077a14583f379058f76a8aecd43c62dc8c0f41766650d725275ac4a1024100bb32d133edc2e048d463388b7be9cb4be29f4b6250be603e70e3647501c97ddde20a4e71be95fd5e71784e25aca4baf25be5738aae59bbfe1c997781447a2b24":PSA_ALG_RSA_PKCS1V15_SIGN(PSA_ALG_SHA_256):"ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015":128:PSA_ERROR_INVALID_ARGUMENT
@@ -4206,9 +4230,53 @@ depends_on:PSA_WANT_ALG_RSA_PSS:PSA_WANT_ALG_SHA_256:PSA_WANT_KEY_TYPE_ECC_KEY_P
sign_hash_fail:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1):"ab45435712649cb30bbddac49197eebf2740ffc7f874d9244c3460f54f322d3a":PSA_ALG_RSA_PSS(PSA_ALG_SHA_256):"9ac4335b469bbd791439248504dd0d49c71349a295fee5a1c68507f45a9e1c7b":72:PSA_ERROR_INVALID_ARGUMENT
PSA sign hash: deterministic ECDSA not supported
-depends_on:!PSA_WANT_ALG_DETERMINISTIC_ECDSA:PSA_WANT_ALG_SHA_256:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:MBEDTLS_PK_PARSE_C:MBEDTLS_ECP_DP_SECP384R1_ENABLED
+depends_on:!PSA_WANT_ALG_DETERMINISTIC_ECDSA:PSA_WANT_ALG_SHA_256:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:MBEDTLS_PK_PARSE_C:PSA_WANT_ECC_SECP_R1_384
sign_hash_fail:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1):"3f5d8d9be280b5696cc5cc9f94cf8af7e6b61dd6592b2ab2b3a4c607450417ec327dcdcaed7c10053d719a0574f0a76a":PSA_ALG_DETERMINISTIC_ECDSA( PSA_ALG_SHA_256 ):"2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824":96:PSA_ERROR_NOT_SUPPORTED
+PSA sign hash int (ops=inf): det ECDSA SECP256R1 SHA-256, out buf too small
+depends_on:PSA_WANT_ALG_DETERMINISTIC_ECDSA:PSA_WANT_ALG_SHA_256:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:MBEDTLS_PK_PARSE_C:PSA_WANT_ECC_SECP_R1_256
+sign_hash_fail_interruptible:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1):"ab45435712649cb30bbddac49197eebf2740ffc7f874d9244c3460f54f322d3a":PSA_ALG_DETERMINISTIC_ECDSA( PSA_ALG_SHA_256 ):"9ac4335b469bbd791439248504dd0d49c71349a295fee5a1c68507f45a9e1c7b":63:PSA_SUCCESS:PSA_ERROR_BUFFER_TOO_SMALL:PSA_INTERRUPTIBLE_MAX_OPS_UNLIMITED
+
+PSA sign hash int (ops=min): det ECDSA SECP256R1 SHA-256, out buf too small
+depends_on:PSA_WANT_ALG_DETERMINISTIC_ECDSA:PSA_WANT_ALG_SHA_256:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:MBEDTLS_PK_PARSE_C:PSA_WANT_ECC_SECP_R1_256
+sign_hash_fail_interruptible:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1):"ab45435712649cb30bbddac49197eebf2740ffc7f874d9244c3460f54f322d3a":PSA_ALG_DETERMINISTIC_ECDSA( PSA_ALG_SHA_256 ):"9ac4335b469bbd791439248504dd0d49c71349a295fee5a1c68507f45a9e1c7b":63:PSA_SUCCESS:PSA_ERROR_BUFFER_TOO_SMALL:1
+
+PSA sign hash int (ops=inf): det ECDSA SECP256R1 SHA-256, empty out buf
+depends_on:PSA_WANT_ALG_DETERMINISTIC_ECDSA:PSA_WANT_ALG_SHA_256:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:MBEDTLS_PK_PARSE_C:PSA_WANT_ECC_SECP_R1_256
+sign_hash_fail_interruptible:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1):"ab45435712649cb30bbddac49197eebf2740ffc7f874d9244c3460f54f322d3a":PSA_ALG_DETERMINISTIC_ECDSA( PSA_ALG_SHA_256 ):"9ac4335b469bbd791439248504dd0d49c71349a295fee5a1c68507f45a9e1c7b":0:PSA_SUCCESS:PSA_ERROR_BUFFER_TOO_SMALL:PSA_INTERRUPTIBLE_MAX_OPS_UNLIMITED
+
+PSA sign hash int (ops=min): det ECDSA SECP256R1 SHA-256, empty out buf
+depends_on:PSA_WANT_ALG_DETERMINISTIC_ECDSA:PSA_WANT_ALG_SHA_256:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:MBEDTLS_PK_PARSE_C:PSA_WANT_ECC_SECP_R1_256
+sign_hash_fail_interruptible:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1):"ab45435712649cb30bbddac49197eebf2740ffc7f874d9244c3460f54f322d3a":PSA_ALG_DETERMINISTIC_ECDSA( PSA_ALG_SHA_256 ):"9ac4335b469bbd791439248504dd0d49c71349a295fee5a1c68507f45a9e1c7b":0:PSA_SUCCESS:PSA_ERROR_BUFFER_TOO_SMALL:1
+
+PSA sign hash int (ops=inf): det ECDSA SECP256R1, invld hash alg (0)
+depends_on:PSA_WANT_ALG_DETERMINISTIC_ECDSA:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:MBEDTLS_PK_PARSE_C:PSA_WANT_ECC_SECP_R1_256
+sign_hash_fail_interruptible:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1):"ab45435712649cb30bbddac49197eebf2740ffc7f874d9244c3460f54f322d3a":PSA_ALG_DETERMINISTIC_ECDSA( 0 ):"9ac4335b469bbd791439248504dd0d49c71349a295fee5a1c68507f45a9e1c7b":72:PSA_SUCCESS:PSA_ERROR_INVALID_ARGUMENT:PSA_INTERRUPTIBLE_MAX_OPS_UNLIMITED
+
+PSA sign hash int (ops=min): det ECDSA SECP256R1, invld hash alg (0)
+depends_on:PSA_WANT_ALG_DETERMINISTIC_ECDSA:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:MBEDTLS_PK_PARSE_C:PSA_WANT_ECC_SECP_R1_256
+sign_hash_fail_interruptible:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1):"ab45435712649cb30bbddac49197eebf2740ffc7f874d9244c3460f54f322d3a":PSA_ALG_DETERMINISTIC_ECDSA( 0 ):"9ac4335b469bbd791439248504dd0d49c71349a295fee5a1c68507f45a9e1c7b":72:PSA_SUCCESS:PSA_ERROR_INVALID_ARGUMENT:1
+
+PSA sign hash int: det ECDSA SECP256R1, invld hash alg (wildcard)
+depends_on:PSA_WANT_ALG_DETERMINISTIC_ECDSA:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:MBEDTLS_PK_PARSE_C:PSA_WANT_ECC_SECP_R1_256
+sign_hash_fail_interruptible:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1):"ab45435712649cb30bbddac49197eebf2740ffc7f874d9244c3460f54f322d3a":PSA_ALG_DETERMINISTIC_ECDSA( PSA_ALG_ANY_HASH ):"9ac4335b469bbd791439248504dd0d49c71349a295fee5a1c68507f45a9e1c7b":72:PSA_ERROR_INVALID_ARGUMENT:PSA_ERROR_BAD_STATE:PSA_INTERRUPTIBLE_MAX_OPS_UNLIMITED
+
+PSA sign hash int: invld alg for ECC key
+depends_on:PSA_WANT_ALG_RSA_PSS:PSA_WANT_ALG_SHA_256:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:PSA_WANT_ECC_SECP_R1_256:MBEDTLS_PK_PARSE_C
+sign_hash_fail_interruptible:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1):"ab45435712649cb30bbddac49197eebf2740ffc7f874d9244c3460f54f322d3a":PSA_ALG_RSA_PSS(PSA_ALG_SHA_256):"9ac4335b469bbd791439248504dd0d49c71349a295fee5a1c68507f45a9e1c7b":72:PSA_ERROR_NOT_SUPPORTED:PSA_ERROR_BAD_STATE:PSA_INTERRUPTIBLE_MAX_OPS_UNLIMITED
+
+PSA sign hash int: ECDSA not supported
+depends_on:!PSA_WANT_ALG_DETERMINISTIC_ECDSA:!PSA_WANT_ALG_ECDSA:PSA_WANT_ALG_SHA_256:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:MBEDTLS_PK_PARSE_C:PSA_WANT_ECC_SECP_R1_384
+sign_hash_fail_interruptible:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1):"3f5d8d9be280b5696cc5cc9f94cf8af7e6b61dd6592b2ab2b3a4c607450417ec327dcdcaed7c10053d719a0574f0a76a":PSA_ALG_DETERMINISTIC_ECDSA( PSA_ALG_SHA_256 ):"2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824":96:PSA_ERROR_NOT_SUPPORTED:PSA_ERROR_BAD_STATE:PSA_INTERRUPTIBLE_MAX_OPS_UNLIMITED
+
+PSA sign hash int (ops=inf): det ECDSA not supported
+depends_on:!PSA_WANT_ALG_DETERMINISTIC_ECDSA:PSA_WANT_ALG_ECDSA:PSA_WANT_ALG_SHA_256:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:MBEDTLS_PK_PARSE_C:PSA_WANT_ECC_SECP_R1_384
+sign_hash_fail_interruptible:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1):"3f5d8d9be280b5696cc5cc9f94cf8af7e6b61dd6592b2ab2b3a4c607450417ec327dcdcaed7c10053d719a0574f0a76a":PSA_ALG_DETERMINISTIC_ECDSA( PSA_ALG_SHA_256 ):"2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824":96:PSA_SUCCESS:PSA_ERROR_NOT_SUPPORTED:PSA_INTERRUPTIBLE_MAX_OPS_UNLIMITED
+
+PSA sign hash int (ops=min): det ECDSA not supported
+depends_on:!PSA_WANT_ALG_DETERMINISTIC_ECDSA:PSA_WANT_ALG_ECDSA:PSA_WANT_ALG_SHA_256:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:MBEDTLS_PK_PARSE_C:PSA_WANT_ECC_SECP_R1_384
+sign_hash_fail_interruptible:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1):"3f5d8d9be280b5696cc5cc9f94cf8af7e6b61dd6592b2ab2b3a4c607450417ec327dcdcaed7c10053d719a0574f0a76a":PSA_ALG_DETERMINISTIC_ECDSA( PSA_ALG_SHA_256 ):"2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824":96:PSA_SUCCESS:PSA_ERROR_NOT_SUPPORTED:1
+
PSA sign/verify hash: RSA PKCS#1 v1.5, raw
depends_on:PSA_WANT_ALG_RSA_PKCS1V15_SIGN:PSA_WANT_KEY_TYPE_RSA_KEY_PAIR:MBEDTLS_PK_PARSE_C
sign_verify_hash:PSA_KEY_TYPE_RSA_KEY_PAIR:"3082025e02010002818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc3020301000102818100874bf0ffc2f2a71d14671ddd0171c954d7fdbf50281e4f6d99ea0e1ebcf82faa58e7b595ffb293d1abe17f110b37c48cc0f36c37e84d876621d327f64bbe08457d3ec4098ba2fa0a319fba411c2841ed7be83196a8cdf9daa5d00694bc335fc4c32217fe0488bce9cb7202e59468b1ead119000477db2ca797fac19eda3f58c1024100e2ab760841bb9d30a81d222de1eb7381d82214407f1b975cbbfe4e1a9467fd98adbd78f607836ca5be1928b9d160d97fd45c12d6b52e2c9871a174c66b488113024100c5ab27602159ae7d6f20c3c2ee851e46dc112e689e28d5fcbbf990a99ef8a90b8bb44fd36467e7fc1789ceb663abda338652c3c73f111774902e840565927091024100b6cdbd354f7df579a63b48b3643e353b84898777b48b15f94e0bfc0567a6ae5911d57ad6409cf7647bf96264e9bd87eb95e263b7110b9a1f9f94acced0fafa4d024071195eec37e8d257decfc672b07ae639f10cbb9b0c739d0c809968d644a94e3fd6ed9287077a14583f379058f76a8aecd43c62dc8c0f41766650d725275ac4a1024100bb32d133edc2e048d463388b7be9cb4be29f4b6250be603e70e3647501c97ddde20a4e71be95fd5e71784e25aca4baf25be5738aae59bbfe1c997781447a2b24":PSA_ALG_RSA_PKCS1V15_SIGN_RAW:"616263"
@@ -4249,6 +4317,54 @@ PSA sign/verify hash: deterministic ECDSA SECP384R1 SHA-256
depends_on:PSA_WANT_ALG_DETERMINISTIC_ECDSA:PSA_WANT_ALG_SHA_256:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:MBEDTLS_PK_PARSE_C:PSA_WANT_ECC_SECP_R1_384
sign_verify_hash:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1):"3f5d8d9be280b5696cc5cc9f94cf8af7e6b61dd6592b2ab2b3a4c607450417ec327dcdcaed7c10053d719a0574f0a76a":PSA_ALG_DETERMINISTIC_ECDSA( PSA_ALG_SHA_256 ):"9ac4335b469bbd791439248504dd0d49c71349a295fee5a1c68507f45a9e1c7b"
+PSA sign/vrfy hash int (ops=inf): rand ECDSA SECP256R1 SHA-256
+depends_on:PSA_WANT_ALG_ECDSA:PSA_WANT_ALG_SHA_256:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:MBEDTLS_PK_PARSE_C:PSA_WANT_ECC_SECP_R1_256
+sign_verify_hash_interruptible:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1):"ab45435712649cb30bbddac49197eebf2740ffc7f874d9244c3460f54f322d3a":PSA_ALG_ECDSA(PSA_ALG_SHA_256):"9ac4335b469bbd791439248504dd0d49c71349a295fee5a1c68507f45a9e1c7b":PSA_INTERRUPTIBLE_MAX_OPS_UNLIMITED
+
+PSA sign/vrfy hash int (ops=min): rand ECDSA SECP256R1 SHA-256
+depends_on:PSA_WANT_ALG_ECDSA:PSA_WANT_ALG_SHA_256:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:MBEDTLS_PK_PARSE_C:PSA_WANT_ECC_SECP_R1_256
+sign_verify_hash_interruptible:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1):"ab45435712649cb30bbddac49197eebf2740ffc7f874d9244c3460f54f322d3a":PSA_ALG_ECDSA(PSA_ALG_SHA_256):"9ac4335b469bbd791439248504dd0d49c71349a295fee5a1c68507f45a9e1c7b":1
+
+PSA sign/vrfy hash int (ops=inf): det ECDSA SECP256R1 SHA-256
+depends_on:PSA_WANT_ALG_DETERMINISTIC_ECDSA:PSA_WANT_ALG_SHA_256:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:MBEDTLS_PK_PARSE_C:PSA_WANT_ECC_SECP_R1_256
+sign_verify_hash_interruptible:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1):"ab45435712649cb30bbddac49197eebf2740ffc7f874d9244c3460f54f322d3a":PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_256):"9ac4335b469bbd791439248504dd0d49c71349a295fee5a1c68507f45a9e1c7b":PSA_INTERRUPTIBLE_MAX_OPS_UNLIMITED
+
+PSA sign/vrfy hash int (ops=min): det ECDSA SECP256R1 SHA-256
+depends_on:PSA_WANT_ALG_DETERMINISTIC_ECDSA:PSA_WANT_ALG_SHA_256:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:MBEDTLS_PK_PARSE_C:PSA_WANT_ECC_SECP_R1_256
+sign_verify_hash_interruptible:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1):"ab45435712649cb30bbddac49197eebf2740ffc7f874d9244c3460f54f322d3a":PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_256):"9ac4335b469bbd791439248504dd0d49c71349a295fee5a1c68507f45a9e1c7b":1
+
+PSA sign/vrfy hash int (ops=inf): rand ECDSA SECP256R1 SHA-384
+depends_on:PSA_WANT_ALG_ECDSA:PSA_WANT_ALG_SHA_384:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:MBEDTLS_PK_PARSE_C:PSA_WANT_ECC_SECP_R1_256:MBEDTLS_HAS_ALG_SHA_384_VIA_MD_OR_PSA
+sign_verify_hash_interruptible:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1):"ab45435712649cb30bbddac49197eebf2740ffc7f874d9244c3460f54f322d3a":PSA_ALG_ECDSA(PSA_ALG_SHA_384):"59e1748777448c69de6b800d7a33bbfb9ff1b463e44354c3553bcdb9c666fa90125a3c79f90397bdf5f6a13de828684f":PSA_INTERRUPTIBLE_MAX_OPS_UNLIMITED
+
+PSA sign/vrfy hash int (ops=min): rand ECDSA SECP256R1 SHA-384
+depends_on:PSA_WANT_ALG_ECDSA:PSA_WANT_ALG_SHA_384:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:MBEDTLS_PK_PARSE_C:PSA_WANT_ECC_SECP_R1_256:MBEDTLS_HAS_ALG_SHA_384_VIA_MD_OR_PSA
+sign_verify_hash_interruptible:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1):"ab45435712649cb30bbddac49197eebf2740ffc7f874d9244c3460f54f322d3a":PSA_ALG_ECDSA(PSA_ALG_SHA_384):"59e1748777448c69de6b800d7a33bbfb9ff1b463e44354c3553bcdb9c666fa90125a3c79f90397bdf5f6a13de828684f":1
+
+PSA sign/vrfy hash int (ops=inf): det ECDSA SECP256R1 SHA-384
+depends_on:PSA_WANT_ALG_DETERMINISTIC_ECDSA:PSA_WANT_ALG_SHA_384:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:MBEDTLS_PK_PARSE_C:PSA_WANT_ECC_SECP_R1_256:MBEDTLS_HAS_ALG_SHA_384_VIA_MD_OR_PSA
+sign_verify_hash_interruptible:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1):"ab45435712649cb30bbddac49197eebf2740ffc7f874d9244c3460f54f322d3a":PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_384):"59e1748777448c69de6b800d7a33bbfb9ff1b463e44354c3553bcdb9c666fa90125a3c79f90397bdf5f6a13de828684f":PSA_INTERRUPTIBLE_MAX_OPS_UNLIMITED
+
+PSA sign/vrfy hash int (ops=min): det ECDSA SECP256R1 SHA-384
+depends_on:PSA_WANT_ALG_DETERMINISTIC_ECDSA:PSA_WANT_ALG_SHA_384:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:MBEDTLS_PK_PARSE_C:PSA_WANT_ECC_SECP_R1_256:MBEDTLS_HAS_ALG_SHA_384_VIA_MD_OR_PSA
+sign_verify_hash_interruptible:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1):"ab45435712649cb30bbddac49197eebf2740ffc7f874d9244c3460f54f322d3a":PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_384):"59e1748777448c69de6b800d7a33bbfb9ff1b463e44354c3553bcdb9c666fa90125a3c79f90397bdf5f6a13de828684f":1
+
+PSA sign/vrfy hash int (ops=inf): rand ECDSA SECP384R1 SHA-256
+depends_on:PSA_WANT_ALG_ECDSA:PSA_WANT_ALG_SHA_256:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:MBEDTLS_PK_PARSE_C:PSA_WANT_ECC_SECP_R1_384
+sign_verify_hash_interruptible:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1):"3f5d8d9be280b5696cc5cc9f94cf8af7e6b61dd6592b2ab2b3a4c607450417ec327dcdcaed7c10053d719a0574f0a76a":PSA_ALG_ECDSA(PSA_ALG_SHA_256):"9ac4335b469bbd791439248504dd0d49c71349a295fee5a1c68507f45a9e1c7b":PSA_INTERRUPTIBLE_MAX_OPS_UNLIMITED
+
+PSA sign/vrfy hash int (ops=min): rand ECDSA SECP384R1 SHA-256
+depends_on:PSA_WANT_ALG_ECDSA:PSA_WANT_ALG_SHA_256:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:MBEDTLS_PK_PARSE_C:PSA_WANT_ECC_SECP_R1_384
+sign_verify_hash_interruptible:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1):"3f5d8d9be280b5696cc5cc9f94cf8af7e6b61dd6592b2ab2b3a4c607450417ec327dcdcaed7c10053d719a0574f0a76a":PSA_ALG_ECDSA(PSA_ALG_SHA_256):"9ac4335b469bbd791439248504dd0d49c71349a295fee5a1c68507f45a9e1c7b":1
+
+PSA sign/vrfy hash int (ops=inf): det ECDSA SECP384R1 SHA-256
+depends_on:PSA_WANT_ALG_DETERMINISTIC_ECDSA:PSA_WANT_ALG_SHA_256:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:MBEDTLS_PK_PARSE_C:PSA_WANT_ECC_SECP_R1_384
+sign_verify_hash_interruptible:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1):"3f5d8d9be280b5696cc5cc9f94cf8af7e6b61dd6592b2ab2b3a4c607450417ec327dcdcaed7c10053d719a0574f0a76a":PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_256):"9ac4335b469bbd791439248504dd0d49c71349a295fee5a1c68507f45a9e1c7b":PSA_INTERRUPTIBLE_MAX_OPS_UNLIMITED
+
+PSA sign/vrfy hash int (ops=min): det ECDSA SECP384R1 SHA-256
+depends_on:PSA_WANT_ALG_DETERMINISTIC_ECDSA:PSA_WANT_ALG_SHA_256:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:MBEDTLS_PK_PARSE_C:PSA_WANT_ECC_SECP_R1_384
+sign_verify_hash_interruptible:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1):"3f5d8d9be280b5696cc5cc9f94cf8af7e6b61dd6592b2ab2b3a4c607450417ec327dcdcaed7c10053d719a0574f0a76a":PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_256):"9ac4335b469bbd791439248504dd0d49c71349a295fee5a1c68507f45a9e1c7b":1
+
PSA verify hash: RSA PKCS#1 v1.5 SHA-256, good signature
depends_on:PSA_WANT_ALG_RSA_PKCS1V15_SIGN:PSA_WANT_ALG_SHA_256:PSA_WANT_KEY_TYPE_RSA_PUBLIC_KEY:MBEDTLS_PK_PARSE_C
verify_hash:PSA_KEY_TYPE_RSA_PUBLIC_KEY:"30818902818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc30203010001":PSA_ALG_RSA_PKCS1V15_SIGN(PSA_ALG_SHA_256):"ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad":"a73664d55b39c7ea6c1e5b5011724a11e1d7073d3a68f48c836fad153a1d91b6abdbc8f69da13b206cc96af6363b114458b026af14b24fab8929ed634c6a2acace0bcc62d9bb6a984afbcbfcd3a0608d32a2bae535b9cd1ecdf9dd281db1e0025c3bfb5512963ec3b98ddaa69e38bc3c84b1b61a04e5648640856aacc6fc7311"
@@ -4369,6 +4485,14 @@ PSA verify hash with keypair: ECDSA SECP256R1, good
depends_on:PSA_WANT_ALG_ECDSA:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:MBEDTLS_PK_PARSE_C:PSA_WANT_ECC_SECP_R1_256
verify_hash:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1):"ab45435712649cb30bbddac49197eebf2740ffc7f874d9244c3460f54f322d3a":PSA_ALG_ECDSA_ANY:"9ac4335b469bbd791439248504dd0d49c71349a295fee5a1c68507f45a9e1c7b":"6a3399f69421ffe1490377adf2ea1f117d81a63cf5bf22e918d51175eb259151ce95d7c26cc04e25503e2f7a1ec3573e3c2412534bb4a19b3a7811742f49f50f"
+PSA vrfy hash int: ECDSA SECP256R1, good
+depends_on:PSA_WANT_ALG_ECDSA:PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY:MBEDTLS_PK_PARSE_C:PSA_WANT_ECC_SECP_R1_256
+verify_hash_interruptible:PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1):"04dea5e45d0ea37fc566232a508f4ad20ea13d47e4bf5fa4d54a57a0ba012042087097496efc583fed8b24a5b9be9a51de063f5a00a8b698a16fd7f29b5485f320":PSA_ALG_ECDSA_ANY:"9ac4335b469bbd791439248504dd0d49c71349a295fee5a1c68507f45a9e1c7b":"6a3399f69421ffe1490377adf2ea1f117d81a63cf5bf22e918d51175eb259151ce95d7c26cc04e25503e2f7a1ec3573e3c2412534bb4a19b3a7811742f49f50f":PSA_INTERRUPTIBLE_MAX_OPS_UNLIMITED
+
+PSA vrfy hash int w/keypair: ECDSA SECP256R1, good
+depends_on:PSA_WANT_ALG_ECDSA:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:MBEDTLS_PK_PARSE_C:PSA_WANT_ECC_SECP_R1_256
+verify_hash_interruptible:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1):"ab45435712649cb30bbddac49197eebf2740ffc7f874d9244c3460f54f322d3a":PSA_ALG_ECDSA_ANY:"9ac4335b469bbd791439248504dd0d49c71349a295fee5a1c68507f45a9e1c7b":"6a3399f69421ffe1490377adf2ea1f117d81a63cf5bf22e918d51175eb259151ce95d7c26cc04e25503e2f7a1ec3573e3c2412534bb4a19b3a7811742f49f50f":PSA_INTERRUPTIBLE_MAX_OPS_UNLIMITED
+
PSA verify hash: ECDSA SECP256R1, wrong signature size (correct but ASN1-encoded)
depends_on:PSA_WANT_ALG_ECDSA:PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY:MBEDTLS_PK_PARSE_C:PSA_WANT_ECC_SECP_R1_256
verify_hash_fail:PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1):"04dea5e45d0ea37fc566232a508f4ad20ea13d47e4bf5fa4d54a57a0ba012042087097496efc583fed8b24a5b9be9a51de063f5a00a8b698a16fd7f29b5485f320":PSA_ALG_ECDSA_ANY:"9ac4335b469bbd791439248504dd0d49c71349a295fee5a1c68507f45a9e1c7b":"304502206a3399f69421ffe1490377adf2ea1f117d81a63cf5bf22e918d51175eb259151022100ce95d7c26cc04e25503e2f7a1ec3573e3c2412534bb4a19b3a7811742f49f50f":PSA_ERROR_INVALID_SIGNATURE
@@ -4397,6 +4521,50 @@ PSA verify hash: invalid algorithm for ECC key
depends_on:PSA_WANT_ALG_RSA_PSS:PSA_WANT_ALG_SHA_256:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:MBEDTLS_PK_PARSE_C:PSA_WANT_ECC_SECP_R1_256
verify_hash_fail:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1):"ab45435712649cb30bbddac49197eebf2740ffc7f874d9244c3460f54f322d3a":PSA_ALG_RSA_PSS(PSA_ALG_SHA_256):"":"":PSA_ERROR_INVALID_ARGUMENT
+PSA vrfy hash int: ECDSA SECP256R1, wrong sig size (correct but ASN1-encoded)
+depends_on:PSA_WANT_ALG_ECDSA:PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY:MBEDTLS_PK_PARSE_C:PSA_WANT_ECC_SECP_R1_256
+verify_hash_fail_interruptible:PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1):"04dea5e45d0ea37fc566232a508f4ad20ea13d47e4bf5fa4d54a57a0ba012042087097496efc583fed8b24a5b9be9a51de063f5a00a8b698a16fd7f29b5485f320":PSA_ALG_ECDSA_ANY:"9ac4335b469bbd791439248504dd0d49c71349a295fee5a1c68507f45a9e1c7b":"304502206a3399f69421ffe1490377adf2ea1f117d81a63cf5bf22e918d51175eb259151022100ce95d7c26cc04e25503e2f7a1ec3573e3c2412534bb4a19b3a7811742f49f50f":PSA_ERROR_INVALID_SIGNATURE:PSA_ERROR_BAD_STATE:PSA_INTERRUPTIBLE_MAX_OPS_UNLIMITED
+
+PSA vrfy hash int (ops=inf): ECDSA SECP256R1, wrong sig of correct size
+depends_on:PSA_WANT_ALG_ECDSA:PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY:MBEDTLS_PK_PARSE_C:PSA_WANT_ECC_SECP_R1_256
+verify_hash_fail_interruptible:PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1):"04dea5e45d0ea37fc566232a508f4ad20ea13d47e4bf5fa4d54a57a0ba012042087097496efc583fed8b24a5b9be9a51de063f5a00a8b698a16fd7f29b5485f320":PSA_ALG_ECDSA_ANY:"9ac4335b469bbd791439248504dd0d49c71349a295fee5a1c68507f45a9e1c7b":"6a3399f69421ffe1490377adf2ea1f117d81a63cf5bf22e918d51175eb259151ce95d7c26cc04e25503e2f7a1ec3573e3c2412534bb4a19b3a7811742f49f50e":PSA_SUCCESS:PSA_ERROR_INVALID_SIGNATURE:PSA_INTERRUPTIBLE_MAX_OPS_UNLIMITED
+
+PSA vrfy hash int (ops=min): ECDSA SECP256R1, wrong sig of correct size
+depends_on:PSA_WANT_ALG_ECDSA:PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY:MBEDTLS_PK_PARSE_C:PSA_WANT_ECC_SECP_R1_256
+verify_hash_fail_interruptible:PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1):"04dea5e45d0ea37fc566232a508f4ad20ea13d47e4bf5fa4d54a57a0ba012042087097496efc583fed8b24a5b9be9a51de063f5a00a8b698a16fd7f29b5485f320":PSA_ALG_ECDSA_ANY:"9ac4335b469bbd791439248504dd0d49c71349a295fee5a1c68507f45a9e1c7b":"6a3399f69421ffe1490377adf2ea1f117d81a63cf5bf22e918d51175eb259151ce95d7c26cc04e25503e2f7a1ec3573e3c2412534bb4a19b3a7811742f49f50e":PSA_SUCCESS:PSA_ERROR_INVALID_SIGNATURE:1
+
+PSA vrfy hash int: ECDSA SECP256R1, wrong sig (empty)
+depends_on:PSA_WANT_ALG_ECDSA:PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY:MBEDTLS_PK_PARSE_C:PSA_WANT_ECC_SECP_R1_256
+verify_hash_fail_interruptible:PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1):"04dea5e45d0ea37fc566232a508f4ad20ea13d47e4bf5fa4d54a57a0ba012042087097496efc583fed8b24a5b9be9a51de063f5a00a8b698a16fd7f29b5485f320":PSA_ALG_ECDSA_ANY:"9ac4335b469bbd791439248504dd0d49c71349a295fee5a1c68507f45a9e1c7b":"":PSA_ERROR_INVALID_SIGNATURE:PSA_ERROR_BAD_STATE:PSA_INTERRUPTIBLE_MAX_OPS_UNLIMITED
+
+PSA vrfy hash int: ECDSA SECP256R1, wrong sig (truncated)
+depends_on:PSA_WANT_ALG_ECDSA:PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY:MBEDTLS_PK_PARSE_C:PSA_WANT_ECC_SECP_R1_256
+verify_hash_fail_interruptible:PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1):"04dea5e45d0ea37fc566232a508f4ad20ea13d47e4bf5fa4d54a57a0ba012042087097496efc583fed8b24a5b9be9a51de063f5a00a8b698a16fd7f29b5485f320":PSA_ALG_ECDSA_ANY:"9ac4335b469bbd791439248504dd0d49c71349a295fee5a1c68507f45a9e1c7b":"6a3399f69421ffe1490377adf2ea1f117d81a63cf5bf22e918d51175eb259151ce95d7c26cc04e25503e2f7a1ec3573e3c2412534bb4a19b3a7811742f49f5":PSA_ERROR_INVALID_SIGNATURE:PSA_ERROR_BAD_STATE:PSA_INTERRUPTIBLE_MAX_OPS_UNLIMITED
+
+PSA vrfy hash int: ECDSA SECP256R1, wrong sig (trailing junk)
+depends_on:PSA_WANT_ALG_ECDSA:PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY:MBEDTLS_PK_PARSE_C:PSA_WANT_ECC_SECP_R1_256
+verify_hash_fail_interruptible:PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1):"04dea5e45d0ea37fc566232a508f4ad20ea13d47e4bf5fa4d54a57a0ba012042087097496efc583fed8b24a5b9be9a51de063f5a00a8b698a16fd7f29b5485f320":PSA_ALG_ECDSA_ANY:"9ac4335b469bbd791439248504dd0d49c71349a295fee5a1c68507f45a9e1c7b":"6a3399f69421ffe1490377adf2ea1f117d81a63cf5bf22e918d51175eb259151ce95d7c26cc04e25503e2f7a1ec3573e3c2412534bb4a19b3a7811742f49f50f21":PSA_ERROR_INVALID_SIGNATURE:PSA_ERROR_BAD_STATE:PSA_INTERRUPTIBLE_MAX_OPS_UNLIMITED
+
+PSA vrfy hash int: ECDSA SECP256R1, wrong sig (leading junk)
+depends_on:PSA_WANT_ALG_ECDSA:PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY:MBEDTLS_PK_PARSE_C:PSA_WANT_ECC_SECP_R1_256
+verify_hash_fail_interruptible:PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1):"04dea5e45d0ea37fc566232a508f4ad20ea13d47e4bf5fa4d54a57a0ba012042087097496efc583fed8b24a5b9be9a51de063f5a00a8b698a16fd7f29b5485f320":PSA_ALG_ECDSA_ANY:"9ac4335b469bbd791439248504dd0d49c71349a295fee5a1c68507f45a9e1c7b":"216a3399f69421ffe1490377adf2ea1f117d81a63cf5bf22e918d51175eb259151ce95d7c26cc04e25503e2f7a1ec3573e3c2412534bb4a19b3a7811742f49f50f":PSA_ERROR_INVALID_SIGNATURE:PSA_ERROR_BAD_STATE:PSA_INTERRUPTIBLE_MAX_OPS_UNLIMITED
+
+PSA vrfy hash int: invld alg for ECC key
+depends_on:PSA_WANT_ALG_RSA_PSS:PSA_WANT_ALG_SHA_256:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:MBEDTLS_PK_PARSE_C:PSA_WANT_ECC_SECP_R1_256
+verify_hash_fail_interruptible:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1):"ab45435712649cb30bbddac49197eebf2740ffc7f874d9244c3460f54f322d3a":PSA_ALG_RSA_PSS(PSA_ALG_SHA_256):"":"":PSA_ERROR_NOT_SUPPORTED:PSA_ERROR_BAD_STATE:PSA_INTERRUPTIBLE_MAX_OPS_UNLIMITED
+
+PSA sign/vrfy hash int state test: randomized ECDSA SECP256R1 SHA-256
+depends_on:PSA_WANT_ALG_ECDSA:PSA_WANT_ALG_SHA_256:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:MBEDTLS_PK_PARSE_C:PSA_WANT_ECC_SECP_R1_256
+interruptible_signverify_hash_state_test:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1):"ab45435712649cb30bbddac49197eebf2740ffc7f874d9244c3460f54f322d3a":PSA_ALG_ECDSA(PSA_ALG_SHA_256):"9ac4335b469bbd791439248504dd0d49c71349a295fee5a1c68507f45a9e1c7b"
+
+PSA sign/vrfy hash int neg tests: randomized ECDSA SECP256R1 SHA-256
+depends_on:PSA_WANT_ALG_ECDSA:PSA_WANT_ALG_SHA_256:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:MBEDTLS_PK_PARSE_C:PSA_WANT_ECC_SECP_R1_256
+interruptible_signverify_hash_negative_tests:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1):"ab45435712649cb30bbddac49197eebf2740ffc7f874d9244c3460f54f322d3a":PSA_ALG_ECDSA(PSA_ALG_SHA_256):"9ac4335b469bbd791439248504dd0d49c71349a295fee5a1c68507f45a9e1c7b"
+
+PSA sign/vrfy hash int max ops tests: randomized ECDSA SECP256R1 SHA-256
+depends_on:PSA_WANT_ALG_ECDSA:PSA_WANT_ALG_SHA_256:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:MBEDTLS_PK_PARSE_C:PSA_WANT_ECC_SECP_R1_256
+interruptible_signverify_hash_maxops_tests:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1):"ab45435712649cb30bbddac49197eebf2740ffc7f874d9244c3460f54f322d3a":PSA_ALG_ECDSA(PSA_ALG_SHA_256):"9ac4335b469bbd791439248504dd0d49c71349a295fee5a1c68507f45a9e1c7b"
+
PSA sign message: RSA PKCS#1 v1.5 SHA-256
depends_on:PSA_WANT_ALG_RSA_PKCS1V15_SIGN:PSA_WANT_ALG_SHA_256:PSA_WANT_KEY_TYPE_RSA_KEY_PAIR:MBEDTLS_PK_PARSE_C
sign_message_deterministic:PSA_KEY_TYPE_RSA_KEY_PAIR:"3082025e02010002818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc3020301000102818100874bf0ffc2f2a71d14671ddd0171c954d7fdbf50281e4f6d99ea0e1ebcf82faa58e7b595ffb293d1abe17f110b37c48cc0f36c37e84d876621d327f64bbe08457d3ec4098ba2fa0a319fba411c2841ed7be83196a8cdf9daa5d00694bc335fc4c32217fe0488bce9cb7202e59468b1ead119000477db2ca797fac19eda3f58c1024100e2ab760841bb9d30a81d222de1eb7381d82214407f1b975cbbfe4e1a9467fd98adbd78f607836ca5be1928b9d160d97fd45c12d6b52e2c9871a174c66b488113024100c5ab27602159ae7d6f20c3c2ee851e46dc112e689e28d5fcbbf990a99ef8a90b8bb44fd36467e7fc1789ceb663abda338652c3c73f111774902e840565927091024100b6cdbd354f7df579a63b48b3643e353b84898777b48b15f94e0bfc0567a6ae5911d57ad6409cf7647bf96264e9bd87eb95e263b7110b9a1f9f94acced0fafa4d024071195eec37e8d257decfc672b07ae639f10cbb9b0c739d0c809968d644a94e3fd6ed9287077a14583f379058f76a8aecd43c62dc8c0f41766650d725275ac4a1024100bb32d133edc2e048d463388b7be9cb4be29f4b6250be603e70e3647501c97ddde20a4e71be95fd5e71784e25aca4baf25be5738aae59bbfe1c997781447a2b24":PSA_ALG_RSA_PKCS1V15_SIGN(PSA_ALG_SHA_256):"616263":"a73664d55b39c7ea6c1e5b5011724a11e1d7073d3a68f48c836fad153a1d91b6abdbc8f69da13b206cc96af6363b114458b026af14b24fab8929ed634c6a2acace0bcc62d9bb6a984afbcbfcd3a0608d32a2bae535b9cd1ecdf9dd281db1e0025c3bfb5512963ec3b98ddaa69e38bc3c84b1b61a04e5648640856aacc6fc7311"
diff --git a/tests/suites/test_suite_psa_crypto.function b/tests/suites/test_suite_psa_crypto.function
index c414b65fa..20e43c6ac 100644
--- a/tests/suites/test_suite_psa_crypto.function
+++ b/tests/suites/test_suite_psa_crypto.function
@@ -1220,6 +1220,34 @@ typedef enum {
INJECT_ANTICIPATE_KEY_DERIVATION_2,
} ecjpake_injected_failure_t;
+#if defined(MBEDTLS_ECP_RESTARTABLE)
+
+static void interruptible_signverify_get_minmax_completes(uint32_t max_ops,
+ psa_status_t expected_status,
+ size_t *min_completes,
+ size_t *max_completes)
+{
+
+ /* This is slightly contrived, but we only really know that with a minimum
+ value of max_ops that a successful operation should take more than one op
+ to complete, and likewise that with a max_ops of
+ PSA_INTERRUPTIBLE_MAX_OPS_UNLIMITED, it should complete in one go. */
+ if (max_ops == 0 || max_ops == 1) {
+
+ if (expected_status == PSA_SUCCESS) {
+ *min_completes = 2;
+ } else {
+ *min_completes = 1;
+ }
+
+ *max_completes = PSA_INTERRUPTIBLE_MAX_OPS_UNLIMITED;
+ } else {
+ *min_completes = 1;
+ *max_completes = 1;
+ }
+}
+#endif /* MBEDTLS_ECP_RESTARTABLE */
+
/* END_HEADER */
/* BEGIN_DEPENDENCIES
@@ -6444,6 +6472,117 @@ exit:
}
/* END_CASE */
+/* BEGIN_CASE depends_on:MBEDTLS_ECP_RESTARTABLE */
+void sign_hash_interruptible(int key_type_arg, data_t *key_data,
+ int alg_arg, data_t *input_data,
+ data_t *output_data, int max_ops_arg)
+{
+ mbedtls_svc_key_id_t key = MBEDTLS_SVC_KEY_ID_INIT;
+ psa_key_type_t key_type = key_type_arg;
+ psa_algorithm_t alg = alg_arg;
+ size_t key_bits;
+ unsigned char *signature = NULL;
+ size_t signature_size;
+ size_t signature_length = 0xdeadbeef;
+ psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+ psa_status_t status = PSA_OPERATION_INCOMPLETE;
+ uint32_t num_ops = 0;
+ uint32_t max_ops = max_ops_arg;
+ size_t num_ops_prior = 0;
+ size_t num_completes = 0;
+ size_t min_completes = 0;
+ size_t max_completes = 0;
+
+ psa_sign_hash_interruptible_operation_t operation =
+ psa_sign_hash_interruptible_operation_init();
+
+ PSA_ASSERT(psa_crypto_init());
+
+ psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_SIGN_HASH);
+ psa_set_key_algorithm(&attributes, alg);
+ psa_set_key_type(&attributes, key_type);
+
+ PSA_ASSERT(psa_import_key(&attributes, key_data->x, key_data->len,
+ &key));
+ PSA_ASSERT(psa_get_key_attributes(key, &attributes));
+ key_bits = psa_get_key_bits(&attributes);
+
+ /* Allocate a buffer which has the size advertised by the
+ * library. */
+ signature_size = PSA_SIGN_OUTPUT_SIZE(key_type,
+ key_bits, alg);
+ TEST_ASSERT(signature_size != 0);
+ TEST_LE_U(signature_size, PSA_SIGNATURE_MAX_SIZE);
+ ASSERT_ALLOC(signature, signature_size);
+
+ psa_interruptible_set_max_ops(max_ops);
+
+ interruptible_signverify_get_minmax_completes(max_ops, PSA_SUCCESS,
+ &min_completes, &max_completes);
+
+ num_ops_prior = psa_sign_hash_get_num_ops(&operation);
+ TEST_ASSERT(num_ops_prior == 0);
+
+ /* Start performing the signature. */
+ PSA_ASSERT(psa_sign_hash_start(&operation, key, alg,
+ input_data->x, input_data->len));
+
+ num_ops_prior = psa_sign_hash_get_num_ops(&operation);
+ TEST_ASSERT(num_ops_prior == 0);
+
+ /* Continue performing the signature until complete. */
+ do {
+ status = psa_sign_hash_complete(&operation, signature, signature_size,
+ &signature_length);
+
+ num_completes++;
+
+ if (status == PSA_SUCCESS || status == PSA_OPERATION_INCOMPLETE) {
+ num_ops = psa_sign_hash_get_num_ops(&operation);
+ /* We are asserting here that every complete makes progress
+ * (completes some ops), which is true of the internal
+ * implementation and probably any implementation, however this is
+ * not mandated by the PSA specification. */
+ TEST_ASSERT(num_ops > num_ops_prior);
+
+ num_ops_prior = num_ops;
+
+ /* Ensure calling get_num_ops() twice still returns the same
+ * number of ops as previously reported. */
+ num_ops = psa_sign_hash_get_num_ops(&operation);
+
+ TEST_EQUAL(num_ops, num_ops_prior);
+ }
+ } while (status == PSA_OPERATION_INCOMPLETE);
+
+ TEST_ASSERT(status == PSA_SUCCESS);
+
+ TEST_LE_U(min_completes, num_completes);
+ TEST_LE_U(num_completes, max_completes);
+
+ /* Verify that the signature is what is expected. */
+ ASSERT_COMPARE(output_data->x, output_data->len,
+ signature, signature_length);
+
+ PSA_ASSERT(psa_sign_hash_abort(&operation));
+
+ num_ops = psa_sign_hash_get_num_ops(&operation);
+ TEST_ASSERT(num_ops == 0);
+
+exit:
+
+ /*
+ * Key attributes may have been returned by psa_get_key_attributes()
+ * thus reset them as required.
+ */
+ psa_reset_key_attributes(&attributes);
+
+ psa_destroy_key(key);
+ mbedtls_free(signature);
+ PSA_DONE();
+}
+/* END_CASE */
+
/* BEGIN_CASE */
void sign_hash_fail(int key_type_arg, data_t *key_data,
int alg_arg, data_t *input_data,
@@ -6489,6 +6628,123 @@ exit:
}
/* END_CASE */
+/* BEGIN_CASE depends_on:MBEDTLS_ECP_RESTARTABLE */
+void sign_hash_fail_interruptible(int key_type_arg, data_t *key_data,
+ int alg_arg, data_t *input_data,
+ int signature_size_arg,
+ int expected_start_status_arg,
+ int expected_complete_status_arg,
+ int max_ops_arg)
+{
+ mbedtls_svc_key_id_t key = MBEDTLS_SVC_KEY_ID_INIT;
+ psa_key_type_t key_type = key_type_arg;
+ psa_algorithm_t alg = alg_arg;
+ size_t signature_size = signature_size_arg;
+ psa_status_t actual_status;
+ psa_status_t expected_start_status = expected_start_status_arg;
+ psa_status_t expected_complete_status = expected_complete_status_arg;
+ unsigned char *signature = NULL;
+ size_t signature_length = 0xdeadbeef;
+ uint32_t num_ops = 0;
+ uint32_t max_ops = max_ops_arg;
+ size_t num_ops_prior = 0;
+ size_t num_completes = 0;
+ size_t min_completes = 0;
+ size_t max_completes = 0;
+
+ psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+ psa_sign_hash_interruptible_operation_t operation =
+ psa_sign_hash_interruptible_operation_init();
+
+ ASSERT_ALLOC(signature, signature_size);
+
+ PSA_ASSERT(psa_crypto_init());
+
+ psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_SIGN_HASH);
+ psa_set_key_algorithm(&attributes, alg);
+ psa_set_key_type(&attributes, key_type);
+
+ PSA_ASSERT(psa_import_key(&attributes, key_data->x, key_data->len,
+ &key));
+
+ psa_interruptible_set_max_ops(max_ops);
+
+ interruptible_signverify_get_minmax_completes(max_ops,
+ expected_complete_status,
+ &min_completes,
+ &max_completes);
+
+ num_ops_prior = psa_sign_hash_get_num_ops(&operation);
+ TEST_ASSERT(num_ops_prior == 0);
+
+ /* Start performing the signature. */
+ actual_status = psa_sign_hash_start(&operation, key, alg,
+ input_data->x, input_data->len);
+
+ TEST_EQUAL(actual_status, expected_start_status);
+
+ if (expected_start_status != PSA_SUCCESS) {
+ actual_status = psa_sign_hash_start(&operation, key, alg,
+ input_data->x, input_data->len);
+
+ TEST_EQUAL(actual_status, PSA_ERROR_BAD_STATE);
+ }
+
+ num_ops_prior = psa_sign_hash_get_num_ops(&operation);
+ TEST_ASSERT(num_ops_prior == 0);
+
+ /* Continue performing the signature until complete. */
+ do {
+ actual_status = psa_sign_hash_complete(&operation, signature,
+ signature_size,
+ &signature_length);
+
+ num_completes++;
+
+ if (actual_status == PSA_SUCCESS ||
+ actual_status == PSA_OPERATION_INCOMPLETE) {
+ num_ops = psa_sign_hash_get_num_ops(&operation);
+ /* We are asserting here that every complete makes progress
+ * (completes some ops), which is true of the internal
+ * implementation and probably any implementation, however this is
+ * not mandated by the PSA specification. */
+ TEST_ASSERT(num_ops > num_ops_prior);
+
+ num_ops_prior = num_ops;
+ }
+ } while (actual_status == PSA_OPERATION_INCOMPLETE);
+
+ TEST_EQUAL(actual_status, expected_complete_status);
+
+ /* Check that another complete returns BAD_STATE. */
+ actual_status = psa_sign_hash_complete(&operation, signature,
+ signature_size,
+ &signature_length);
+
+ TEST_EQUAL(actual_status, PSA_ERROR_BAD_STATE);
+
+ PSA_ASSERT(psa_sign_hash_abort(&operation));
+
+ num_ops = psa_sign_hash_get_num_ops(&operation);
+ TEST_ASSERT(num_ops == 0);
+
+ /* The value of *signature_length is unspecified on error, but
+ * whatever it is, it should be less than signature_size, so that
+ * if the caller tries to read *signature_length bytes without
+ * checking the error code then they don't overflow a buffer. */
+ TEST_LE_U(signature_length, signature_size);
+
+ TEST_LE_U(min_completes, num_completes);
+ TEST_LE_U(num_completes, max_completes);
+
+exit:
+ psa_reset_key_attributes(&attributes);
+ psa_destroy_key(key);
+ mbedtls_free(signature);
+ PSA_DONE();
+}
+/* END_CASE */
+
/* BEGIN_CASE */
void sign_verify_hash(int key_type_arg, data_t *key_data,
int alg_arg, data_t *input_data)
@@ -6559,6 +6815,137 @@ exit:
}
/* END_CASE */
+/* BEGIN_CASE depends_on:MBEDTLS_ECP_RESTARTABLE */
+void sign_verify_hash_interruptible(int key_type_arg, data_t *key_data,
+ int alg_arg, data_t *input_data,
+ int max_ops_arg)
+{
+ mbedtls_svc_key_id_t key = MBEDTLS_SVC_KEY_ID_INIT;
+ psa_key_type_t key_type = key_type_arg;
+ psa_algorithm_t alg = alg_arg;
+ size_t key_bits;
+ unsigned char *signature = NULL;
+ size_t signature_size;
+ size_t signature_length = 0xdeadbeef;
+ psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+ psa_status_t status = PSA_OPERATION_INCOMPLETE;
+ uint32_t max_ops = max_ops_arg;
+ size_t num_completes = 0;
+ size_t min_completes = 0;
+ size_t max_completes = 0;
+
+ psa_sign_hash_interruptible_operation_t sign_operation =
+ psa_sign_hash_interruptible_operation_init();
+ psa_verify_hash_interruptible_operation_t verify_operation =
+ psa_verify_hash_interruptible_operation_init();
+
+ PSA_ASSERT(psa_crypto_init());
+
+ psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_SIGN_HASH |
+ PSA_KEY_USAGE_VERIFY_HASH);
+ psa_set_key_algorithm(&attributes, alg);
+ psa_set_key_type(&attributes, key_type);
+
+ PSA_ASSERT(psa_import_key(&attributes, key_data->x, key_data->len,
+ &key));
+ PSA_ASSERT(psa_get_key_attributes(key, &attributes));
+ key_bits = psa_get_key_bits(&attributes);
+
+ /* Allocate a buffer which has the size advertised by the
+ * library. */
+ signature_size = PSA_SIGN_OUTPUT_SIZE(key_type,
+ key_bits, alg);
+ TEST_ASSERT(signature_size != 0);
+ TEST_LE_U(signature_size, PSA_SIGNATURE_MAX_SIZE);
+ ASSERT_ALLOC(signature, signature_size);
+
+ psa_interruptible_set_max_ops(max_ops);
+
+ interruptible_signverify_get_minmax_completes(max_ops, PSA_SUCCESS,
+ &min_completes, &max_completes);
+
+ /* Start performing the signature. */
+ PSA_ASSERT(psa_sign_hash_start(&sign_operation, key, alg,
+ input_data->x, input_data->len));
+
+ /* Continue performing the signature until complete. */
+ do {
+
+ status = psa_sign_hash_complete(&sign_operation, signature,
+ signature_size,
+ &signature_length);
+
+ num_completes++;
+ } while (status == PSA_OPERATION_INCOMPLETE);
+
+ TEST_ASSERT(status == PSA_SUCCESS);
+
+ TEST_LE_U(min_completes, num_completes);
+ TEST_LE_U(num_completes, max_completes);
+
+ PSA_ASSERT(psa_sign_hash_abort(&sign_operation));
+
+ /* Check that the signature length looks sensible. */
+ TEST_LE_U(signature_length, signature_size);
+ TEST_ASSERT(signature_length > 0);
+
+ num_completes = 0;
+
+ /* Start verification. */
+ PSA_ASSERT(psa_verify_hash_start(&verify_operation, key, alg,
+ input_data->x, input_data->len,
+ signature, signature_length));
+
+ /* Continue performing the signature until complete. */
+ do {
+ status = psa_verify_hash_complete(&verify_operation);
+
+ num_completes++;
+ } while (status == PSA_OPERATION_INCOMPLETE);
+
+ TEST_ASSERT(status == PSA_SUCCESS);
+
+ TEST_LE_U(min_completes, num_completes);
+ TEST_LE_U(num_completes, max_completes);
+
+ PSA_ASSERT(psa_verify_hash_abort(&verify_operation));
+
+ verify_operation = psa_verify_hash_interruptible_operation_init();
+
+ if (input_data->len != 0) {
+ /* Flip a bit in the input and verify that the signature is now
+ * detected as invalid. Flip a bit at the beginning, not at the end,
+ * because ECDSA may ignore the last few bits of the input. */
+ input_data->x[0] ^= 1;
+
+ /* Start verification. */
+ PSA_ASSERT(psa_verify_hash_start(&verify_operation, key, alg,
+ input_data->x, input_data->len,
+ signature, signature_length));
+
+ /* Continue performing the signature until complete. */
+ do {
+ status = psa_verify_hash_complete(&verify_operation);
+ } while (status == PSA_OPERATION_INCOMPLETE);
+
+ TEST_ASSERT(status == PSA_ERROR_INVALID_SIGNATURE);
+ }
+
+ PSA_ASSERT(psa_verify_hash_abort(&verify_operation));
+
+exit:
+ /*
+ * Key attributes may have been returned by psa_get_key_attributes()
+ * thus reset them as required.
+ */
+ psa_reset_key_attributes(&attributes);
+
+ psa_destroy_key(key);
+ mbedtls_free(signature);
+ PSA_DONE();
+}
+/* END_CASE */
+
/* BEGIN_CASE */
void verify_hash(int key_type_arg, data_t *key_data,
int alg_arg, data_t *hash_data,
@@ -6591,6 +6978,97 @@ exit:
}
/* END_CASE */
+/* BEGIN_CASE depends_on:MBEDTLS_ECP_RESTARTABLE */
+void verify_hash_interruptible(int key_type_arg, data_t *key_data,
+ int alg_arg, data_t *hash_data,
+ data_t *signature_data, int max_ops_arg)
+{
+ mbedtls_svc_key_id_t key = MBEDTLS_SVC_KEY_ID_INIT;
+ psa_key_type_t key_type = key_type_arg;
+ psa_algorithm_t alg = alg_arg;
+ psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+ psa_status_t status = PSA_OPERATION_INCOMPLETE;
+ uint32_t num_ops = 0;
+ uint32_t max_ops = max_ops_arg;
+ size_t num_ops_prior = 0;
+ size_t num_completes = 0;
+ size_t min_completes = 0;
+ size_t max_completes = 0;
+
+ psa_verify_hash_interruptible_operation_t operation =
+ psa_verify_hash_interruptible_operation_init();
+
+ TEST_LE_U(signature_data->len, PSA_SIGNATURE_MAX_SIZE);
+
+ PSA_ASSERT(psa_crypto_init());
+
+ psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_VERIFY_HASH);
+ psa_set_key_algorithm(&attributes, alg);
+ psa_set_key_type(&attributes, key_type);
+
+ PSA_ASSERT(psa_import_key(&attributes, key_data->x, key_data->len,
+ &key));
+
+ psa_interruptible_set_max_ops(max_ops);
+
+ interruptible_signverify_get_minmax_completes(max_ops, PSA_SUCCESS,
+ &min_completes, &max_completes);
+
+ num_ops_prior = psa_verify_hash_get_num_ops(&operation);
+
+ TEST_ASSERT(num_ops_prior == 0);
+
+ /* Start verification. */
+ PSA_ASSERT(psa_verify_hash_start(&operation, key, alg,
+ hash_data->x, hash_data->len,
+ signature_data->x, signature_data->len)
+ );
+
+ num_ops_prior = psa_verify_hash_get_num_ops(&operation);
+
+ TEST_ASSERT(num_ops_prior == 0);
+
+ /* Continue performing the signature until complete. */
+ do {
+ status = psa_verify_hash_complete(&operation);
+
+ num_completes++;
+
+ if (status == PSA_SUCCESS || status == PSA_OPERATION_INCOMPLETE) {
+ num_ops = psa_verify_hash_get_num_ops(&operation);
+ /* We are asserting here that every complete makes progress
+ * (completes some ops), which is true of the internal
+ * implementation and probably any implementation, however this is
+ * not mandated by the PSA specification. */
+ TEST_ASSERT(num_ops > num_ops_prior);
+
+ num_ops_prior = num_ops;
+
+ /* Ensure calling get_num_ops() twice still returns the same
+ * number of ops as previously reported. */
+ num_ops = psa_verify_hash_get_num_ops(&operation);
+
+ TEST_EQUAL(num_ops, num_ops_prior);
+ }
+ } while (status == PSA_OPERATION_INCOMPLETE);
+
+ TEST_ASSERT(status == PSA_SUCCESS);
+
+ TEST_LE_U(min_completes, num_completes);
+ TEST_LE_U(num_completes, max_completes);
+
+ PSA_ASSERT(psa_verify_hash_abort(&operation));
+
+ num_ops = psa_verify_hash_get_num_ops(&operation);
+ TEST_ASSERT(num_ops == 0);
+
+exit:
+ psa_reset_key_attributes(&attributes);
+ psa_destroy_key(key);
+ PSA_DONE();
+}
+/* END_CASE */
+
/* BEGIN_CASE */
void verify_hash_fail(int key_type_arg, data_t *key_data,
int alg_arg, data_t *hash_data,
@@ -6625,6 +7103,479 @@ exit:
}
/* END_CASE */
+/* BEGIN_CASE depends_on:MBEDTLS_ECP_RESTARTABLE */
+void verify_hash_fail_interruptible(int key_type_arg, data_t *key_data,
+ int alg_arg, data_t *hash_data,
+ data_t *signature_data,
+ int expected_start_status_arg,
+ int expected_complete_status_arg,
+ int max_ops_arg)
+{
+ mbedtls_svc_key_id_t key = MBEDTLS_SVC_KEY_ID_INIT;
+ psa_key_type_t key_type = key_type_arg;
+ psa_algorithm_t alg = alg_arg;
+ psa_status_t actual_status;
+ psa_status_t expected_start_status = expected_start_status_arg;
+ psa_status_t expected_complete_status = expected_complete_status_arg;
+ psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+ uint32_t num_ops = 0;
+ uint32_t max_ops = max_ops_arg;
+ size_t num_ops_prior = 0;
+ size_t num_completes = 0;
+ size_t min_completes = 0;
+ size_t max_completes = 0;
+ psa_verify_hash_interruptible_operation_t operation =
+ psa_verify_hash_interruptible_operation_init();
+
+ PSA_ASSERT(psa_crypto_init());
+
+ psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_VERIFY_HASH);
+ psa_set_key_algorithm(&attributes, alg);
+ psa_set_key_type(&attributes, key_type);
+
+ PSA_ASSERT(psa_import_key(&attributes, key_data->x, key_data->len,
+ &key));
+
+ psa_interruptible_set_max_ops(max_ops);
+
+ interruptible_signverify_get_minmax_completes(max_ops,
+ expected_complete_status,
+ &min_completes,
+ &max_completes);
+
+ num_ops_prior = psa_verify_hash_get_num_ops(&operation);
+ TEST_ASSERT(num_ops_prior == 0);
+
+ /* Start verification. */
+ actual_status = psa_verify_hash_start(&operation, key, alg,
+ hash_data->x, hash_data->len,
+ signature_data->x,
+ signature_data->len);
+
+ TEST_EQUAL(actual_status, expected_start_status);
+
+ if (expected_start_status != PSA_SUCCESS) {
+ actual_status = psa_verify_hash_start(&operation, key, alg,
+ hash_data->x, hash_data->len,
+ signature_data->x,
+ signature_data->len);
+
+ TEST_EQUAL(actual_status, PSA_ERROR_BAD_STATE);
+ }
+
+ num_ops_prior = psa_verify_hash_get_num_ops(&operation);
+ TEST_ASSERT(num_ops_prior == 0);
+
+ /* Continue performing the signature until complete. */
+ do {
+ actual_status = psa_verify_hash_complete(&operation);
+
+ num_completes++;
+
+ if (actual_status == PSA_SUCCESS ||
+ actual_status == PSA_OPERATION_INCOMPLETE) {
+ num_ops = psa_verify_hash_get_num_ops(&operation);
+ /* We are asserting here that every complete makes progress
+ * (completes some ops), which is true of the internal
+ * implementation and probably any implementation, however this is
+ * not mandated by the PSA specification. */
+ TEST_ASSERT(num_ops > num_ops_prior);
+
+ num_ops_prior = num_ops;
+ }
+ } while (actual_status == PSA_OPERATION_INCOMPLETE);
+
+ TEST_EQUAL(actual_status, expected_complete_status);
+
+ /* Check that another complete returns BAD_STATE. */
+ actual_status = psa_verify_hash_complete(&operation);
+ TEST_EQUAL(actual_status, PSA_ERROR_BAD_STATE);
+
+ TEST_LE_U(min_completes, num_completes);
+ TEST_LE_U(num_completes, max_completes);
+
+ PSA_ASSERT(psa_verify_hash_abort(&operation));
+
+ num_ops = psa_verify_hash_get_num_ops(&operation);
+ TEST_ASSERT(num_ops == 0);
+
+exit:
+ psa_reset_key_attributes(&attributes);
+ psa_destroy_key(key);
+ PSA_DONE();
+}
+/* END_CASE */
+
+/* BEGIN_CASE depends_on:MBEDTLS_ECP_RESTARTABLE */
+void interruptible_signverify_hash_state_test(int key_type_arg,
+ data_t *key_data, int alg_arg, data_t *input_data)
+{
+ mbedtls_svc_key_id_t key = MBEDTLS_SVC_KEY_ID_INIT;
+ psa_key_type_t key_type = key_type_arg;
+ psa_algorithm_t alg = alg_arg;
+ size_t key_bits;
+ unsigned char *signature = NULL;
+ size_t signature_size;
+ size_t signature_length = 0xdeadbeef;
+ psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+ psa_sign_hash_interruptible_operation_t sign_operation =
+ psa_sign_hash_interruptible_operation_init();
+ psa_verify_hash_interruptible_operation_t verify_operation =
+ psa_verify_hash_interruptible_operation_init();
+
+ PSA_ASSERT(psa_crypto_init());
+
+ psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_SIGN_HASH |
+ PSA_KEY_USAGE_VERIFY_HASH);
+ psa_set_key_algorithm(&attributes, alg);
+ psa_set_key_type(&attributes, key_type);
+
+ PSA_ASSERT(psa_import_key(&attributes, key_data->x, key_data->len,
+ &key));
+ PSA_ASSERT(psa_get_key_attributes(key, &attributes));
+ key_bits = psa_get_key_bits(&attributes);
+
+ /* Allocate a buffer which has the size advertised by the
+ * library. */
+ signature_size = PSA_SIGN_OUTPUT_SIZE(key_type,
+ key_bits, alg);
+ TEST_ASSERT(signature_size != 0);
+ TEST_LE_U(signature_size, PSA_SIGNATURE_MAX_SIZE);
+ ASSERT_ALLOC(signature, signature_size);
+
+ psa_interruptible_set_max_ops(PSA_INTERRUPTIBLE_MAX_OPS_UNLIMITED);
+
+ /* --- Attempt completes prior to starts --- */
+ TEST_EQUAL(psa_sign_hash_complete(&sign_operation, signature,
+ signature_size,
+ &signature_length),
+ PSA_ERROR_BAD_STATE);
+
+ PSA_ASSERT(psa_sign_hash_abort(&sign_operation));
+
+ TEST_EQUAL(psa_verify_hash_complete(&verify_operation),
+ PSA_ERROR_BAD_STATE);
+
+ PSA_ASSERT(psa_verify_hash_abort(&verify_operation));
+
+ /* --- Aborts in all other places. --- */
+ psa_sign_hash_abort(&sign_operation);
+
+ PSA_ASSERT(psa_sign_hash_start(&sign_operation, key, alg,
+ input_data->x, input_data->len));
+
+ PSA_ASSERT(psa_sign_hash_abort(&sign_operation));
+
+ psa_interruptible_set_max_ops(1);
+
+ PSA_ASSERT(psa_sign_hash_start(&sign_operation, key, alg,
+ input_data->x, input_data->len));
+
+ TEST_EQUAL(psa_sign_hash_complete(&sign_operation, signature,
+ signature_size,
+ &signature_length),
+ PSA_OPERATION_INCOMPLETE);
+
+ PSA_ASSERT(psa_sign_hash_abort(&sign_operation));
+
+ psa_interruptible_set_max_ops(PSA_INTERRUPTIBLE_MAX_OPS_UNLIMITED);
+
+ PSA_ASSERT(psa_sign_hash_start(&sign_operation, key, alg,
+ input_data->x, input_data->len));
+
+ PSA_ASSERT(psa_sign_hash_complete(&sign_operation, signature,
+ signature_size,
+ &signature_length));
+
+ PSA_ASSERT(psa_sign_hash_abort(&sign_operation));
+
+ PSA_ASSERT(psa_verify_hash_abort(&verify_operation));
+
+ PSA_ASSERT(psa_verify_hash_start(&verify_operation, key, alg,
+ input_data->x, input_data->len,
+ signature, signature_length));
+
+ PSA_ASSERT(psa_verify_hash_abort(&verify_operation));
+
+ psa_interruptible_set_max_ops(1);
+
+ PSA_ASSERT(psa_verify_hash_start(&verify_operation, key, alg,
+ input_data->x, input_data->len,
+ signature, signature_length));
+
+ TEST_EQUAL(psa_verify_hash_complete(&verify_operation),
+ PSA_OPERATION_INCOMPLETE);
+
+ PSA_ASSERT(psa_verify_hash_abort(&verify_operation));
+
+ psa_interruptible_set_max_ops(PSA_INTERRUPTIBLE_MAX_OPS_UNLIMITED);
+
+ PSA_ASSERT(psa_verify_hash_start(&verify_operation, key, alg,
+ input_data->x, input_data->len,
+ signature, signature_length));
+
+ PSA_ASSERT(psa_verify_hash_complete(&verify_operation));
+
+ PSA_ASSERT(psa_verify_hash_abort(&verify_operation));
+
+ /* --- Attempt double starts. --- */
+
+ PSA_ASSERT(psa_sign_hash_start(&sign_operation, key, alg,
+ input_data->x, input_data->len));
+
+ TEST_EQUAL(psa_sign_hash_start(&sign_operation, key, alg,
+ input_data->x, input_data->len),
+ PSA_ERROR_BAD_STATE);
+
+ PSA_ASSERT(psa_sign_hash_abort(&sign_operation));
+
+ PSA_ASSERT(psa_verify_hash_start(&verify_operation, key, alg,
+ input_data->x, input_data->len,
+ signature, signature_length));
+
+ TEST_EQUAL(psa_verify_hash_start(&verify_operation, key, alg,
+ input_data->x, input_data->len,
+ signature, signature_length),
+ PSA_ERROR_BAD_STATE);
+
+ PSA_ASSERT(psa_verify_hash_abort(&verify_operation));
+
+exit:
+ /*
+ * Key attributes may have been returned by psa_get_key_attributes()
+ * thus reset them as required.
+ */
+ psa_reset_key_attributes(&attributes);
+
+ psa_destroy_key(key);
+ mbedtls_free(signature);
+ PSA_DONE();
+}
+/* END_CASE */
+
+/* BEGIN_CASE depends_on:MBEDTLS_ECP_RESTARTABLE */
+void interruptible_signverify_hash_negative_tests(int key_type_arg,
+ data_t *key_data, int alg_arg, data_t *input_data)
+{
+ mbedtls_svc_key_id_t key = MBEDTLS_SVC_KEY_ID_INIT;
+ psa_key_type_t key_type = key_type_arg;
+ psa_algorithm_t alg = alg_arg;
+ size_t key_bits;
+ unsigned char *signature = NULL;
+ size_t signature_size;
+ size_t signature_length = 0xdeadbeef;
+ psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+ uint8_t *input_buffer = NULL;
+ psa_sign_hash_interruptible_operation_t sign_operation =
+ psa_sign_hash_interruptible_operation_init();
+ psa_verify_hash_interruptible_operation_t verify_operation =
+ psa_verify_hash_interruptible_operation_init();
+
+ PSA_ASSERT(psa_crypto_init());
+
+ psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_SIGN_HASH |
+ PSA_KEY_USAGE_VERIFY_HASH);
+ psa_set_key_algorithm(&attributes, alg);
+ psa_set_key_type(&attributes, key_type);
+
+ PSA_ASSERT(psa_import_key(&attributes, key_data->x, key_data->len,
+ &key));
+ PSA_ASSERT(psa_get_key_attributes(key, &attributes));
+ key_bits = psa_get_key_bits(&attributes);
+
+ /* Allocate a buffer which has the size advertised by the
+ * library. */
+ signature_size = PSA_SIGN_OUTPUT_SIZE(key_type,
+ key_bits, alg);
+ TEST_ASSERT(signature_size != 0);
+ TEST_LE_U(signature_size, PSA_SIGNATURE_MAX_SIZE);
+ ASSERT_ALLOC(signature, signature_size);
+
+ /* --- Ensure changing the max ops mid operation works (operation should
+ * complete successfully after setting max ops to unlimited --- */
+ psa_interruptible_set_max_ops(1);
+
+ PSA_ASSERT(psa_sign_hash_start(&sign_operation, key, alg,
+ input_data->x, input_data->len));
+
+ TEST_EQUAL(psa_sign_hash_complete(&sign_operation, signature,
+ signature_size,
+ &signature_length),
+ PSA_OPERATION_INCOMPLETE);
+
+ psa_interruptible_set_max_ops(PSA_INTERRUPTIBLE_MAX_OPS_UNLIMITED);
+
+ PSA_ASSERT(psa_sign_hash_complete(&sign_operation, signature,
+ signature_size,
+ &signature_length));
+
+ PSA_ASSERT(psa_sign_hash_abort(&sign_operation));
+
+ psa_interruptible_set_max_ops(1);
+
+ PSA_ASSERT(psa_verify_hash_start(&verify_operation, key, alg,
+ input_data->x, input_data->len,
+ signature, signature_length));
+
+ TEST_EQUAL(psa_verify_hash_complete(&verify_operation),
+ PSA_OPERATION_INCOMPLETE);
+
+ psa_interruptible_set_max_ops(PSA_INTERRUPTIBLE_MAX_OPS_UNLIMITED);
+
+ PSA_ASSERT(psa_verify_hash_complete(&verify_operation));
+
+ PSA_ASSERT(psa_verify_hash_abort(&verify_operation));
+
+ /* --- Change function inputs mid run, to cause an error (sign only,
+ * verify passes all inputs to start. --- */
+
+ psa_interruptible_set_max_ops(1);
+
+ PSA_ASSERT(psa_sign_hash_start(&sign_operation, key, alg,
+ input_data->x, input_data->len));
+
+ TEST_EQUAL(psa_sign_hash_complete(&sign_operation, signature,
+ signature_size,
+ &signature_length),
+ PSA_OPERATION_INCOMPLETE);
+
+ TEST_EQUAL(psa_sign_hash_complete(&sign_operation, signature,
+ 0,
+ &signature_length),
+ PSA_ERROR_BUFFER_TOO_SMALL);
+
+ /* And test that this invalidates the operation. */
+ TEST_EQUAL(psa_sign_hash_complete(&sign_operation, signature,
+ 0,
+ &signature_length),
+ PSA_ERROR_BAD_STATE);
+
+ PSA_ASSERT(psa_sign_hash_abort(&sign_operation));
+
+ /* Trash the hash buffer in between start and complete, to ensure
+ * no reliance on external buffers. */
+ psa_interruptible_set_max_ops(PSA_INTERRUPTIBLE_MAX_OPS_UNLIMITED);
+
+ input_buffer = mbedtls_calloc(1, input_data->len);
+ TEST_ASSERT(input_buffer != NULL);
+
+ memcpy(input_buffer, input_data->x, input_data->len);
+
+ PSA_ASSERT(psa_sign_hash_start(&sign_operation, key, alg,
+ input_buffer, input_data->len));
+
+ memset(input_buffer, '!', input_data->len);
+ mbedtls_free(input_buffer);
+ input_buffer = NULL;
+
+ PSA_ASSERT(psa_sign_hash_complete(&sign_operation, signature,
+ signature_size,
+ &signature_length));
+
+ PSA_ASSERT(psa_sign_hash_abort(&sign_operation));
+
+ input_buffer = mbedtls_calloc(1, input_data->len);
+ TEST_ASSERT(input_buffer != NULL);
+
+ memcpy(input_buffer, input_data->x, input_data->len);
+
+ PSA_ASSERT(psa_verify_hash_start(&verify_operation, key, alg,
+ input_buffer, input_data->len,
+ signature, signature_length));
+
+ memset(input_buffer, '!', input_data->len);
+ mbedtls_free(input_buffer);
+ input_buffer = NULL;
+
+ PSA_ASSERT(psa_verify_hash_complete(&verify_operation));
+
+ PSA_ASSERT(psa_verify_hash_abort(&verify_operation));
+
+exit:
+ /*
+ * Key attributes may have been returned by psa_get_key_attributes()
+ * thus reset them as required.
+ */
+ psa_reset_key_attributes(&attributes);
+
+ psa_destroy_key(key);
+ mbedtls_free(signature);
+ PSA_DONE();
+}
+/* END_CASE */
+
+/* BEGIN_CASE depends_on:MBEDTLS_ECP_RESTARTABLE */
+void interruptible_signverify_hash_maxops_tests(int key_type_arg,
+ data_t *key_data, int alg_arg, data_t *input_data)
+{
+ mbedtls_svc_key_id_t key = MBEDTLS_SVC_KEY_ID_INIT;
+ psa_key_type_t key_type = key_type_arg;
+ psa_algorithm_t alg = alg_arg;
+ psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+ size_t key_bits;
+ unsigned char *signature = NULL;
+ size_t signature_size;
+ psa_sign_hash_interruptible_operation_t sign_operation =
+ psa_sign_hash_interruptible_operation_init();
+ psa_verify_hash_interruptible_operation_t verify_operation =
+ psa_verify_hash_interruptible_operation_init();
+
+ PSA_ASSERT(psa_crypto_init());
+
+ psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_SIGN_HASH |
+ PSA_KEY_USAGE_VERIFY_HASH);
+ psa_set_key_algorithm(&attributes, alg);
+ psa_set_key_type(&attributes, key_type);
+
+ PSA_ASSERT(psa_import_key(&attributes, key_data->x, key_data->len, &key));
+ PSA_ASSERT(psa_get_key_attributes(key, &attributes));
+ key_bits = psa_get_key_bits(&attributes);
+
+ /* Allocate a buffer which has the size advertised by the
+ * library. */
+ signature_size = PSA_SIGN_OUTPUT_SIZE(key_type, key_bits, alg);
+
+ TEST_ASSERT(signature_size != 0);
+ TEST_LE_U(signature_size, PSA_SIGNATURE_MAX_SIZE);
+ ASSERT_ALLOC(signature, signature_size);
+
+ /* Check that default max ops gets set if we don't set it. */
+ PSA_ASSERT(psa_sign_hash_start(&sign_operation, key, alg,
+ input_data->x, input_data->len));
+
+ TEST_EQUAL(psa_interruptible_get_max_ops(),
+ PSA_INTERRUPTIBLE_MAX_OPS_UNLIMITED);
+
+ PSA_ASSERT(psa_sign_hash_abort(&sign_operation));
+
+ PSA_ASSERT(psa_verify_hash_start(&verify_operation, key, alg,
+ input_data->x, input_data->len,
+ signature, signature_size));
+
+ TEST_EQUAL(psa_interruptible_get_max_ops(),
+ PSA_INTERRUPTIBLE_MAX_OPS_UNLIMITED);
+
+ PSA_ASSERT(psa_verify_hash_abort(&verify_operation));
+
+ /* Check that max ops gets set properly. */
+
+ psa_interruptible_set_max_ops(0xbeef);
+
+ TEST_EQUAL(psa_interruptible_get_max_ops(), 0xbeef);
+
+exit:
+ /*
+ * Key attributes may have been returned by psa_get_key_attributes()
+ * thus reset them as required.
+ */
+ psa_reset_key_attributes(&attributes);
+
+ psa_destroy_key(key);
+ mbedtls_free(signature);
+ PSA_DONE();
+}
+/* END_CASE */
+
/* BEGIN_CASE */
void sign_message_deterministic(int key_type_arg,
data_t *key_data,
diff --git a/tests/suites/test_suite_psa_crypto_op_fail.function b/tests/suites/test_suite_psa_crypto_op_fail.function
index 046e3c3a0..970be84b4 100644
--- a/tests/suites/test_suite_psa_crypto_op_fail.function
+++ b/tests/suites/test_suite_psa_crypto_op_fail.function
@@ -221,6 +221,13 @@ void sign_fail(int key_type_arg, data_t *key_data,
uint8_t input[1] = { 'A' };
uint8_t output[PSA_SIGNATURE_MAX_SIZE] = { 0 };
size_t length = SIZE_MAX;
+ psa_sign_hash_interruptible_operation_t sign_operation =
+ psa_sign_hash_interruptible_operation_init();
+
+ psa_verify_hash_interruptible_operation_t verify_operation =
+ psa_verify_hash_interruptible_operation_init();
+
+
PSA_INIT();
@@ -237,6 +244,15 @@ void sign_fail(int key_type_arg, data_t *key_data,
psa_sign_hash(key_id, alg,
input, sizeof(input),
output, sizeof(output), &length));
+
+ if (PSA_KEY_TYPE_IS_ECC(key_type)) {
+ TEST_STATUS(expected_status,
+ psa_sign_hash_start(&sign_operation, key_id, alg,
+ input, sizeof(input)));
+
+ PSA_ASSERT(psa_sign_hash_abort(&sign_operation));
+ }
+
if (!private_only) {
/* Determine a plausible signature size to avoid an INVALID_SIGNATURE
* error based on this. */
@@ -253,6 +269,15 @@ void sign_fail(int key_type_arg, data_t *key_data,
psa_verify_hash(key_id, alg,
input, sizeof(input),
output, output_length));
+
+ if (PSA_KEY_TYPE_IS_ECC(key_type)) {
+ TEST_STATUS(expected_status,
+ psa_verify_hash_start(&verify_operation, key_id, alg,
+ input, sizeof(input),
+ output, output_length));
+
+ PSA_ASSERT(psa_verify_hash_abort(&verify_operation));
+ }
}
exit: