Merge pull request #9785 from waleed-elmelegy-arm/add-iop-export-pub-key-setup-abort

Add PSA interruptible export public-key setup & abort APIs
diff --git a/tests/include/test/psa_test_wrappers.h b/tests/include/test/psa_test_wrappers.h
index 880f34c..904baad 100644
--- a/tests/include/test/psa_test_wrappers.h
+++ b/tests/include/test/psa_test_wrappers.h
@@ -363,7 +363,7 @@
 
 psa_status_t mbedtls_test_wrap_psa_export_public_key_iop_setup(
     psa_export_public_key_iop_t *arg0_operation,
-    psa_key_id_t arg1_key);
+    mbedtls_svc_key_id_t arg1_key);
 #define psa_export_public_key_iop_setup(arg0_operation, arg1_key) \
     mbedtls_test_wrap_psa_export_public_key_iop_setup(arg0_operation, arg1_key)
 
diff --git a/tests/src/psa_test_wrappers.c b/tests/src/psa_test_wrappers.c
index 65d8157..3df0772 100644
--- a/tests/src/psa_test_wrappers.c
+++ b/tests/src/psa_test_wrappers.c
@@ -623,7 +623,7 @@
 /* Wrapper for psa_export_public_key_iop_setup */
 psa_status_t mbedtls_test_wrap_psa_export_public_key_iop_setup(
     psa_export_public_key_iop_t *arg0_operation,
-    psa_key_id_t arg1_key)
+    mbedtls_svc_key_id_t arg1_key)
 {
     psa_status_t status = (psa_export_public_key_iop_setup)(arg0_operation, arg1_key);
     return status;
diff --git a/tf-psa-crypto/core/psa_crypto.c b/tf-psa-crypto/core/psa_crypto.c
index 4fb6ab5..beb17d5 100644
--- a/tf-psa-crypto/core/psa_crypto.c
+++ b/tf-psa-crypto/core/psa_crypto.c
@@ -1665,6 +1665,23 @@
 /* Interruptible ECC Export Public-key */
 /****************************************************************/
 
+#if defined(MBEDTLS_ECP_RESTARTABLE)
+static psa_status_t psa_export_public_key_iop_abort_internal(psa_export_public_key_iop_t *operation)
+{
+    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+
+    if (operation->id == 0) {
+        return PSA_SUCCESS;
+    }
+
+    status = mbedtls_psa_ecp_export_public_key_iop_abort(&operation->ctx);
+
+    operation->id = 0;
+
+    return status;
+}
+#endif
+
 uint32_t psa_export_public_key_iop_get_num_ops(psa_export_public_key_iop_t *operation)
 {
     (void) operation;
@@ -1672,12 +1689,67 @@
 }
 
 psa_status_t psa_export_public_key_iop_setup(psa_export_public_key_iop_t *operation,
-                                             psa_key_id_t key)
+                                             mbedtls_svc_key_id_t key)
 {
+#if defined(MBEDTLS_ECP_RESTARTABLE)
+    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+    psa_status_t unlock_status = PSA_ERROR_CORRUPTION_DETECTED;
+    size_t key_size = 0;
+    psa_key_attributes_t private_key_attributes;
+    psa_key_type_t private_key_type;
+    psa_key_slot_t *slot = NULL;
+
+    if (operation->id != 0 || operation->error_occurred) {
+        return PSA_ERROR_BAD_STATE;
+    }
+
+    /* We only support the builtin/Mbed TLS driver for now. */
+    operation->id = PSA_CRYPTO_MBED_TLS_DRIVER_ID;
+
+    status = psa_get_and_lock_transparent_key_slot_with_policy(key, &slot,
+                                                               0,
+                                                               0);
+    if (status != PSA_SUCCESS) {
+        goto exit;
+    }
+
+    private_key_attributes = slot->attr;
+
+    private_key_type = psa_get_key_type(&private_key_attributes);
+
+    if (!PSA_KEY_TYPE_IS_KEY_PAIR(private_key_type)) {
+        status = PSA_ERROR_INVALID_ARGUMENT;
+        goto exit;
+    }
+
+    if (!PSA_KEY_TYPE_IS_ECC_KEY_PAIR(private_key_type)) {
+        status = PSA_ERROR_NOT_SUPPORTED;
+        goto exit;
+    }
+
+    key_size = PSA_EXPORT_KEY_OUTPUT_SIZE(private_key_type,
+                                          psa_get_key_bits(&private_key_attributes));
+    if (key_size == 0) {
+        status = PSA_ERROR_NOT_SUPPORTED;
+        goto exit;
+    }
+
+    status = mbedtls_psa_ecp_export_public_key_iop_setup(&operation->ctx, slot->key.data,
+                                                         slot->key.bytes, &private_key_attributes);
+
+exit:
+    unlock_status = psa_unregister_read_under_mutex(slot);
+    if (status != PSA_SUCCESS) {
+        psa_export_public_key_iop_abort_internal(operation);
+        operation->error_occurred = 1;
+        return status;
+    }
+    return unlock_status;
+#else
     (void) operation;
     (void) key;
-
     return PSA_ERROR_NOT_SUPPORTED;
+#endif
 }
 
 psa_status_t psa_export_public_key_iop_complete(psa_export_public_key_iop_t *operation,
@@ -1695,9 +1767,19 @@
 
 psa_status_t psa_export_public_key_iop_abort(psa_export_public_key_iop_t *operation)
 {
-    (void) operation;
+#if defined(MBEDTLS_ECP_RESTARTABLE)
+    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
 
-    return PSA_ERROR_NOT_SUPPORTED;
+    status = psa_export_public_key_iop_abort_internal(operation);
+
+    operation->num_ops = 0;
+    operation->error_occurred = 0;
+
+    return status;
+#else
+    (void) operation;
+    return PSA_SUCCESS;
+#endif
 }
 
 /** Validate that a key policy is internally well-formed.
@@ -8443,7 +8525,6 @@
 #endif
 }
 
-
 /****************************************************************/
 /* Module setup */
 /****************************************************************/
diff --git a/tf-psa-crypto/drivers/builtin/src/psa_crypto_ecp.c b/tf-psa-crypto/drivers/builtin/src/psa_crypto_ecp.c
index b2764b0..b58587f 100644
--- a/tf-psa-crypto/drivers/builtin/src/psa_crypto_ecp.c
+++ b/tf-psa-crypto/drivers/builtin/src/psa_crypto_ecp.c
@@ -654,6 +654,41 @@
     return PSA_SUCCESS;
 }
 
+psa_status_t mbedtls_psa_ecp_export_public_key_iop_setup(
+    mbedtls_psa_export_public_key_iop_operation_t *operation,
+    uint8_t *private_key,
+    size_t private_key_len,
+    const psa_key_attributes_t *private_key_attributes)
+{
+    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+
+    status = mbedtls_psa_ecp_load_representation(
+        psa_get_key_type(private_key_attributes),
+        psa_get_key_bits(private_key_attributes),
+        private_key,
+        private_key_len,
+        &operation->key);
+    if (status != PSA_SUCCESS) {
+        goto exit;
+    }
+
+    mbedtls_ecp_restart_init(&operation->restart_ctx);
+    operation->num_ops = 0;
+
+exit:
+    return status;
+}
+
+psa_status_t mbedtls_psa_ecp_export_public_key_iop_abort(
+    mbedtls_psa_export_public_key_iop_operation_t *operation)
+{
+    mbedtls_ecp_keypair_free(operation->key);
+    mbedtls_free(operation->key);
+    mbedtls_ecp_restart_free(&operation->restart_ctx);
+    operation->num_ops = 0;
+    return PSA_SUCCESS;
+}
+
 #endif
 /****************************************************************/
 /* Interruptible ECC Key Agreement */
diff --git a/tf-psa-crypto/drivers/builtin/src/psa_crypto_ecp.h b/tf-psa-crypto/drivers/builtin/src/psa_crypto_ecp.h
index f3ff323..506516d 100644
--- a/tf-psa-crypto/drivers/builtin/src/psa_crypto_ecp.h
+++ b/tf-psa-crypto/drivers/builtin/src/psa_crypto_ecp.h
@@ -121,6 +121,44 @@
     uint8_t *data, size_t data_size, size_t *data_length);
 
 /**
+ * \brief Setup a new interruptible export public-key operation.
+ *
+ *  \param[in] operation                 The \c mbedtls_psa_export_public_key_iop_operation_t to use.
+ *                                       This must be initialized first.
+ *  \param[in] private_key               pointer to private key.
+ *  \param[in] private_key_len           size of \p private_key in bytes.
+ *  \param[in] private_key_attributes    Key attributes of the private key.
+ *
+ *  \retval #PSA_SUCCESS
+ *         The operation started successfully - call \c mbedtls_psa_ecp_export_public_key_iop_complete()
+ *         with the same operation to complete the operation.
+ * \retval #PSA_ERROR_NOT_SUPPORTED
+ *           Either no internal interruptible operations are
+ *           currently supported, or the key attributes are not unsupported.
+ * \retval #PSA_ERROR_INSUFFICIENT_MEMORY
+ *         There was insufficient memory to load the key representation.
+ * \retval #PSA_ERROR_INVALID_ARGUMENT \emptydescription
+ * \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription
+ *
+ */
+psa_status_t mbedtls_psa_ecp_export_public_key_iop_setup(
+    mbedtls_psa_export_public_key_iop_operation_t *operation,
+    uint8_t *private_key,
+    size_t private_key_len,
+    const psa_key_attributes_t *private_key_attributes);
+
+/**
+ * \brief Abort an interruptible export public-key operation.
+ *
+ * \param[in] operation               The \c mbedtls_psa_export_public_key_iop_operation_t to abort.
+ *
+ * \retval #PSA_SUCCESS
+ *         The operation was aborted successfully.
+ */
+psa_status_t mbedtls_psa_ecp_export_public_key_iop_abort(
+    mbedtls_psa_export_public_key_iop_operation_t *operation);
+
+/**
  * \brief Generate an ECP key.
  *
  * \note The signature of the function is that of a PSA driver generate_key
diff --git a/tf-psa-crypto/include/psa/crypto.h b/tf-psa-crypto/include/psa/crypto.h
index c1ef041..6ea945d 100644
--- a/tf-psa-crypto/include/psa/crypto.h
+++ b/tf-psa-crypto/include/psa/crypto.h
@@ -5677,7 +5677,7 @@
  * \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription
  */
 psa_status_t psa_export_public_key_iop_setup(psa_export_public_key_iop_t *operation,
-                                             psa_key_id_t key);
+                                             mbedtls_svc_key_id_t key);
 
 /**
  * \brief                       Continue and eventually complete the action of
diff --git a/tf-psa-crypto/include/psa/crypto_builtin_composites.h b/tf-psa-crypto/include/psa/crypto_builtin_composites.h
index 14e759b..9bd58f9 100644
--- a/tf-psa-crypto/include/psa/crypto_builtin_composites.h
+++ b/tf-psa-crypto/include/psa/crypto_builtin_composites.h
@@ -248,4 +248,22 @@
 #define MBEDTLS_PSA_KEY_AGREEMENT_IOP_INIT { 0 }
 #endif
 
+/* Context structure for the Mbed TLS interruptible export public-key implementation. */
+typedef struct {
+#if defined(MBEDTLS_ECP_C) && defined(MBEDTLS_ECP_RESTARTABLE)
+    mbedtls_ecp_keypair *MBEDTLS_PRIVATE(key);
+    mbedtls_ecp_restart_ctx MBEDTLS_PRIVATE(restart_ctx);
+    uint32_t MBEDTLS_PRIVATE(num_ops);
+#else
+    /* Make the struct non-empty if algs not supported. */
+    unsigned MBEDTLS_PRIVATE(dummy);
+#endif
+} mbedtls_psa_export_public_key_iop_operation_t;
+
+#if defined(MBEDTLS_ECP_C) && defined(MBEDTLS_ECP_RESTARTABLE)
+#define MBEDTLS_PSA_EXPORT_PUBLIC_KEY_IOP_INIT { NULL, MBEDTLS_ECP_RESTART_INIT, 0 }
+#else
+#define MBEDTLS_PSA_EXPORT_PUBLIC_KEY_IOP_INIT { 0 }
+#endif
+
 #endif /* PSA_CRYPTO_BUILTIN_COMPOSITES_H */
diff --git a/tf-psa-crypto/include/psa/crypto_struct.h b/tf-psa-crypto/include/psa/crypto_struct.h
index 09f4c18..d0300da 100644
--- a/tf-psa-crypto/include/psa/crypto_struct.h
+++ b/tf-psa-crypto/include/psa/crypto_struct.h
@@ -584,15 +584,20 @@
      * any driver (i.e. none of the driver contexts are active).
      */
     unsigned int MBEDTLS_PRIVATE(id);
+    mbedtls_psa_export_public_key_iop_operation_t MBEDTLS_PRIVATE(ctx);
+    unsigned int MBEDTLS_PRIVATE(error_occurred) : 1;
+    uint32_t MBEDTLS_PRIVATE(num_ops);
 #endif
 };
+
 #if defined(MBEDTLS_PSA_CRYPTO_CLIENT) && !defined(MBEDTLS_PSA_CRYPTO_C)
 #define PSA_EXPORT_PUBLIC_KEY_IOP_INIT { 0 }
 #else
-#define PSA_EXPORT_PUBLIC_KEY_IOP_INIT { 0 }
+#define PSA_EXPORT_PUBLIC_KEY_IOP_INIT { 0, MBEDTLS_PSA_EXPORT_PUBLIC_KEY_IOP_INIT, 0, 0 }
 #endif
 
-static inline struct psa_export_public_key_iop_s psa_export_public_key_iop_init(void)
+static inline struct psa_export_public_key_iop_s
+psa_export_public_key_iop_init(void)
 {
     const struct psa_export_public_key_iop_s v = PSA_EXPORT_PUBLIC_KEY_IOP_INIT;
 
diff --git a/tf-psa-crypto/tests/suites/test_suite_psa_crypto.data b/tf-psa-crypto/tests/suites/test_suite_psa_crypto.data
index 707e5b0..35073af 100644
--- a/tf-psa-crypto/tests/suites/test_suite_psa_crypto.data
+++ b/tf-psa-crypto/tests/suites/test_suite_psa_crypto.data
@@ -7925,6 +7925,53 @@
 PSA derive persistent key: HKDF SHA-256, exportable
 persistent_key_load_key_from_storage:"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b":PSA_KEY_TYPE_RAW_DATA:1024:PSA_KEY_USAGE_EXPORT:0:DERIVE_KEY
 
+PSA interruptible export public key: ECC, SECP256R1, good
+depends_on:PSA_WANT_ALG_ECDSA:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_GENERATE:PSA_WANT_ECC_SECP_R1_256
+iop_export_public_key:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1):256:PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_VERIFY_HASH:PSA_ALG_ECDSA_ANY:PSA_SUCCESS
+
+PSA interruptible export public key: ECC, Curve25519, good
+depends_on:PSA_WANT_ALG_ECDSA:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_GENERATE:PSA_WANT_ECC_MONTGOMERY_255
+iop_export_public_key:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_MONTGOMERY):255:PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_DERIVE:PSA_ALG_ECDSA_ANY:PSA_SUCCESS
+
+PSA interruptible export public key: ECC, Curve448, good
+depends_on:PSA_WANT_ALG_ECDSA:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_GENERATE:PSA_WANT_ECC_MONTGOMERY_448
+iop_export_public_key:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_MONTGOMERY):448:PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_DERIVE:PSA_ALG_ECDSA_ANY:PSA_SUCCESS
+
+PSA interruptible export public key: ECC, SECP384R1, good
+depends_on:PSA_WANT_ALG_ECDSA:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_GENERATE:PSA_WANT_ECC_SECP_R1_384
+iop_export_public_key:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1):384:PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_VERIFY_HASH:PSA_ALG_ECDSA_ANY:PSA_SUCCESS
+
+PSA interruptible export public key: ECC, SECP521R1, good
+depends_on:PSA_WANT_ALG_ECDSA:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_GENERATE:PSA_WANT_ECC_SECP_R1_521
+iop_export_public_key:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1):521:PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_VERIFY_HASH:PSA_ALG_ECDSA_ANY:PSA_SUCCESS
+
+PSA interruptible export public key: ECC, SECP192K1, good
+depends_on:PSA_WANT_ALG_ECDSA:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_GENERATE:PSA_WANT_ECC_SECP_K1_192
+iop_export_public_key:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_K1):192:PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_VERIFY_HASH:PSA_ALG_ECDSA_ANY:PSA_SUCCESS
+
+PSA interruptible export public key: ECC, SECP256K1, good
+depends_on:PSA_WANT_ALG_ECDSA:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_GENERATE:PSA_WANT_ECC_SECP_K1_256
+iop_export_public_key:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_K1):256:PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_VERIFY_HASH:PSA_ALG_ECDSA_ANY:PSA_SUCCESS
+
+PSA interruptible export public key: ECC, brainpool256r1, good
+depends_on:PSA_WANT_ALG_ECDSA:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_GENERATE:PSA_WANT_ECC_BRAINPOOL_P_R1_256
+iop_export_public_key:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_BRAINPOOL_P_R1):256:PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_VERIFY_HASH:PSA_ALG_ECDSA_ANY:PSA_SUCCESS
+
+PSA interruptible export public key: ECC, brainpool384r1, good
+depends_on:PSA_WANT_ALG_ECDSA:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_GENERATE:PSA_WANT_ECC_BRAINPOOL_P_R1_384
+iop_export_public_key:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_BRAINPOOL_P_R1):384:PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_VERIFY_HASH:PSA_ALG_ECDSA_ANY:PSA_SUCCESS
+
+PSA interruptible export public key: RSA, not ECC key, Not supported
+depends_on:PSA_WANT_ALG_RSA_PSS:PSA_WANT_ALG_SHA_256:PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_GENERATE:PSA_VENDOR_RSA_GENERATE_MIN_KEY_BITS <= 1024
+iop_export_public_key:PSA_KEY_TYPE_RSA_KEY_PAIR:1024:PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_VERIFY_HASH:PSA_ALG_RSA_PSS(PSA_ALG_SHA_256):PSA_ERROR_NOT_SUPPORTED
+
+PSA interruptible export public key: AES, not keypair, Invalid argument
+depends_on:PSA_WANT_ALG_GCM:PSA_WANT_KEY_TYPE_AES
+iop_export_public_key:PSA_KEY_TYPE_AES:128:PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT:PSA_ALG_GCM:PSA_ERROR_INVALID_ARGUMENT
+
+PSA export public-key interruptible object initializers zero properly
+export_public_key_iop_init:
+
 ECP group ID <-> PSA family - SECP192R1
 depends_on:PSA_WANT_ECC_SECP_R1_192
 ecc_conversion_functions:MBEDTLS_ECP_DP_SECP192R1:PSA_ECC_FAMILY_SECP_R1:192
diff --git a/tf-psa-crypto/tests/suites/test_suite_psa_crypto.function b/tf-psa-crypto/tests/suites/test_suite_psa_crypto.function
index 6791062..c555093 100644
--- a/tf-psa-crypto/tests/suites/test_suite_psa_crypto.function
+++ b/tf-psa-crypto/tests/suites/test_suite_psa_crypto.function
@@ -10350,6 +10350,75 @@
 /* END_CASE */
 
 /* BEGIN_CASE */
+void iop_export_public_key(
+    int type_arg,
+    int bits_arg,
+    int usage_arg,
+    int alg_arg,
+    int expected_status_arg)
+{
+    mbedtls_svc_key_id_t iop_key = MBEDTLS_SVC_KEY_ID_INIT;
+    psa_key_type_t type = type_arg;
+    psa_key_usage_t usage = usage_arg;
+    size_t bits = bits_arg;
+    psa_algorithm_t alg = alg_arg;
+    psa_status_t expected_status = expected_status_arg;
+    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+    psa_export_public_key_iop_t export_key_operation = PSA_EXPORT_PUBLIC_KEY_IOP_INIT;
+    psa_status_t status;
+
+    PSA_ASSERT(psa_crypto_init());
+
+    psa_set_key_usage_flags(&attributes, usage);
+    psa_set_key_algorithm(&attributes, alg);
+    psa_set_key_type(&attributes, type);
+    psa_set_key_bits(&attributes, bits);
+
+#if !defined(MBEDTLS_ECP_RESTARTABLE)
+    expected_status = PSA_ERROR_NOT_SUPPORTED;
+#endif
+
+    status = psa_generate_key(&attributes, &iop_key);
+    TEST_EQUAL(status, PSA_SUCCESS);
+
+    status = psa_export_public_key_iop_setup(&export_key_operation, iop_key);
+    TEST_EQUAL(status, expected_status);
+
+#if defined(MBEDTLS_ECP_RESTARTABLE)
+    /* Test calling setup() 2 times consecutively will fail. */
+    status = psa_export_public_key_iop_setup(&export_key_operation, iop_key);
+    TEST_EQUAL(status, PSA_ERROR_BAD_STATE);
+#endif
+
+    TEST_EQUAL(psa_export_public_key_iop_abort(&export_key_operation), PSA_SUCCESS);
+
+    /* Test that after calling abort operation is reset to it's fresh state */
+    status = psa_export_public_key_iop_setup(&export_key_operation, iop_key);
+    TEST_EQUAL(status, expected_status);
+
+exit:
+    psa_export_public_key_iop_abort(&export_key_operation);
+    psa_destroy_key(iop_key);
+    PSA_DONE();
+}
+/* END_CASE */
+
+/* BEGIN_CASE */
+void export_public_key_iop_init()
+{
+    psa_export_public_key_iop_t init = PSA_EXPORT_PUBLIC_KEY_IOP_INIT;
+    psa_export_public_key_iop_t fun = psa_export_public_key_iop_init();
+    psa_export_public_key_iop_t zero;
+
+    memset(&zero, 0, sizeof(zero));
+
+    PSA_ASSERT(psa_export_public_key_iop_abort(&init));
+    PSA_ASSERT(psa_export_public_key_iop_abort(&fun));
+    PSA_ASSERT(psa_export_public_key_iop_abort(&zero));
+}
+/* END_CASE */
+
+/* BEGIN_CASE */
 void generate_key_custom(int type_arg,
                          int bits_arg,
                          int usage_arg,