psasim: add support for key functions that don't need psa_key_attributes_t
Signed-off-by: Tom Cosgrove <tom.cosgrove@arm.com>
diff --git a/tests/psa-client-server/psasim/src/psa_functions_codes.h b/tests/psa-client-server/psasim/src/psa_functions_codes.h
index fbbdea2..04401d1 100644
--- a/tests/psa-client-server/psasim/src/psa_functions_codes.h
+++ b/tests/psa-client-server/psasim/src/psa_functions_codes.h
@@ -36,6 +36,8 @@
PSA_CIPHER_SET_IV,
PSA_CIPHER_UPDATE,
PSA_DESTROY_KEY,
+ PSA_EXPORT_KEY,
+ PSA_EXPORT_PUBLIC_KEY,
PSA_GENERATE_KEY,
PSA_GENERATE_KEY_EXT,
PSA_GENERATE_RANDOM,
@@ -68,6 +70,7 @@
PSA_MAC_VERIFY,
PSA_MAC_VERIFY_FINISH,
PSA_MAC_VERIFY_SETUP,
+ PSA_PURGE_KEY,
PSA_RAW_KEY_AGREEMENT,
PSA_SIGN_HASH,
PSA_SIGN_MESSAGE,
diff --git a/tests/psa-client-server/psasim/src/psa_sim_crypto_client.c b/tests/psa-client-server/psasim/src/psa_sim_crypto_client.c
index 8dd85a3..67a66ff 100644
--- a/tests/psa-client-server/psasim/src/psa_sim_crypto_client.c
+++ b/tests/psa-client-server/psasim/src/psa_sim_crypto_client.c
@@ -2114,6 +2114,166 @@
}
+psa_status_t psa_export_key(
+ mbedtls_svc_key_id_t key,
+ uint8_t *data, size_t data_size,
+ size_t *data_length
+ )
+{
+ uint8_t *ser_params = NULL;
+ uint8_t *ser_result = NULL;
+ size_t result_length;
+ psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+
+ size_t needed = psasim_serialise_begin_needs() +
+ psasim_serialise_mbedtls_svc_key_id_t_needs(key) +
+ psasim_serialise_buffer_needs(data, data_size) +
+ psasim_serialise_size_t_needs(*data_length);
+
+ ser_params = malloc(needed);
+ if (ser_params == NULL) {
+ status = PSA_ERROR_INSUFFICIENT_MEMORY;
+ goto fail;
+ }
+
+ uint8_t *pos = ser_params;
+ size_t remaining = needed;
+ int ok;
+ ok = psasim_serialise_begin(&pos, &remaining);
+ if (!ok) {
+ goto fail;
+ }
+ ok = psasim_serialise_mbedtls_svc_key_id_t(&pos, &remaining, key);
+ if (!ok) {
+ goto fail;
+ }
+ ok = psasim_serialise_buffer(&pos, &remaining, data, data_size);
+ if (!ok) {
+ goto fail;
+ }
+ ok = psasim_serialise_size_t(&pos, &remaining, *data_length);
+ if (!ok) {
+ goto fail;
+ }
+
+ ok = psa_crypto_call(PSA_EXPORT_KEY,
+ ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
+ if (!ok) {
+ printf("PSA_EXPORT_KEY server call failed\n");
+ goto fail;
+ }
+
+ uint8_t *rpos = ser_result;
+ size_t rremain = result_length;
+
+ ok = psasim_deserialise_begin(&rpos, &rremain);
+ if (!ok) {
+ goto fail;
+ }
+
+ ok = psasim_deserialise_psa_status_t(&rpos, &rremain, &status);
+ if (!ok) {
+ goto fail;
+ }
+
+ ok = psasim_deserialise_return_buffer(&rpos, &rremain, data, data_size);
+ if (!ok) {
+ goto fail;
+ }
+
+ ok = psasim_deserialise_size_t(&rpos, &rremain, data_length);
+ if (!ok) {
+ goto fail;
+ }
+
+fail:
+ free(ser_params);
+ free(ser_result);
+
+ return status;
+}
+
+
+psa_status_t psa_export_public_key(
+ mbedtls_svc_key_id_t key,
+ uint8_t *data, size_t data_size,
+ size_t *data_length
+ )
+{
+ uint8_t *ser_params = NULL;
+ uint8_t *ser_result = NULL;
+ size_t result_length;
+ psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+
+ size_t needed = psasim_serialise_begin_needs() +
+ psasim_serialise_mbedtls_svc_key_id_t_needs(key) +
+ psasim_serialise_buffer_needs(data, data_size) +
+ psasim_serialise_size_t_needs(*data_length);
+
+ ser_params = malloc(needed);
+ if (ser_params == NULL) {
+ status = PSA_ERROR_INSUFFICIENT_MEMORY;
+ goto fail;
+ }
+
+ uint8_t *pos = ser_params;
+ size_t remaining = needed;
+ int ok;
+ ok = psasim_serialise_begin(&pos, &remaining);
+ if (!ok) {
+ goto fail;
+ }
+ ok = psasim_serialise_mbedtls_svc_key_id_t(&pos, &remaining, key);
+ if (!ok) {
+ goto fail;
+ }
+ ok = psasim_serialise_buffer(&pos, &remaining, data, data_size);
+ if (!ok) {
+ goto fail;
+ }
+ ok = psasim_serialise_size_t(&pos, &remaining, *data_length);
+ if (!ok) {
+ goto fail;
+ }
+
+ ok = psa_crypto_call(PSA_EXPORT_PUBLIC_KEY,
+ ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
+ if (!ok) {
+ printf("PSA_EXPORT_PUBLIC_KEY server call failed\n");
+ goto fail;
+ }
+
+ uint8_t *rpos = ser_result;
+ size_t rremain = result_length;
+
+ ok = psasim_deserialise_begin(&rpos, &rremain);
+ if (!ok) {
+ goto fail;
+ }
+
+ ok = psasim_deserialise_psa_status_t(&rpos, &rremain, &status);
+ if (!ok) {
+ goto fail;
+ }
+
+ ok = psasim_deserialise_return_buffer(&rpos, &rremain, data, data_size);
+ if (!ok) {
+ goto fail;
+ }
+
+ ok = psasim_deserialise_size_t(&rpos, &rremain, data_length);
+ if (!ok) {
+ goto fail;
+ }
+
+fail:
+ free(ser_params);
+ free(ser_result);
+
+ return status;
+}
+
+
psa_status_t psa_generate_key(
const psa_key_attributes_t *attributes,
mbedtls_svc_key_id_t *key
@@ -4465,6 +4625,64 @@
}
+psa_status_t psa_purge_key(
+ mbedtls_svc_key_id_t key
+ )
+{
+ uint8_t *ser_params = NULL;
+ uint8_t *ser_result = NULL;
+ size_t result_length;
+ psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+
+ size_t needed = psasim_serialise_begin_needs() +
+ psasim_serialise_mbedtls_svc_key_id_t_needs(key);
+
+ ser_params = malloc(needed);
+ if (ser_params == NULL) {
+ status = PSA_ERROR_INSUFFICIENT_MEMORY;
+ goto fail;
+ }
+
+ uint8_t *pos = ser_params;
+ size_t remaining = needed;
+ int ok;
+ ok = psasim_serialise_begin(&pos, &remaining);
+ if (!ok) {
+ goto fail;
+ }
+ ok = psasim_serialise_mbedtls_svc_key_id_t(&pos, &remaining, key);
+ if (!ok) {
+ goto fail;
+ }
+
+ ok = psa_crypto_call(PSA_PURGE_KEY,
+ ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
+ if (!ok) {
+ printf("PSA_PURGE_KEY server call failed\n");
+ goto fail;
+ }
+
+ uint8_t *rpos = ser_result;
+ size_t rremain = result_length;
+
+ ok = psasim_deserialise_begin(&rpos, &rremain);
+ if (!ok) {
+ goto fail;
+ }
+
+ ok = psasim_deserialise_psa_status_t(&rpos, &rremain, &status);
+ if (!ok) {
+ goto fail;
+ }
+
+fail:
+ free(ser_params);
+ free(ser_result);
+
+ return status;
+}
+
+
psa_status_t psa_raw_key_agreement(
psa_algorithm_t alg,
mbedtls_svc_key_id_t private_key,
diff --git a/tests/psa-client-server/psasim/src/psa_sim_crypto_server.c b/tests/psa-client-server/psasim/src/psa_sim_crypto_server.c
index ae80349..41b4bc6 100644
--- a/tests/psa-client-server/psasim/src/psa_sim_crypto_server.c
+++ b/tests/psa-client-server/psasim/src/psa_sim_crypto_server.c
@@ -2415,6 +2415,194 @@
}
// Returns 1 for success, 0 for failure
+int psa_export_key_wrapper(
+ uint8_t *in_params, size_t in_params_len,
+ uint8_t **out_params, size_t *out_params_len)
+{
+ psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+ mbedtls_svc_key_id_t key;
+ uint8_t *data = NULL;
+ size_t data_size;
+ size_t data_length;
+
+ uint8_t *pos = in_params;
+ size_t remaining = in_params_len;
+ uint8_t *result = NULL;
+ int ok;
+
+ ok = psasim_deserialise_begin(&pos, &remaining);
+ if (!ok) {
+ goto fail;
+ }
+
+ ok = psasim_deserialise_mbedtls_svc_key_id_t(&pos, &remaining, &key);
+ if (!ok) {
+ goto fail;
+ }
+
+ ok = psasim_deserialise_buffer(&pos, &remaining, &data, &data_size);
+ if (!ok) {
+ goto fail;
+ }
+
+ ok = psasim_deserialise_size_t(&pos, &remaining, &data_length);
+ if (!ok) {
+ goto fail;
+ }
+
+ // Now we call the actual target function
+
+ status = psa_export_key(
+ key,
+ data, data_size,
+ &data_length
+ );
+
+ // NOTE: Should really check there is no overflow as we go along.
+ size_t result_size =
+ psasim_serialise_begin_needs() +
+ psasim_serialise_psa_status_t_needs(status) +
+ psasim_serialise_buffer_needs(data, data_size) +
+ psasim_serialise_size_t_needs(data_length);
+
+ result = malloc(result_size);
+ if (result == NULL) {
+ goto fail;
+ }
+
+ uint8_t *rpos = result;
+ size_t rremain = result_size;
+
+ ok = psasim_serialise_begin(&rpos, &rremain);
+ if (!ok) {
+ goto fail;
+ }
+
+ ok = psasim_serialise_psa_status_t(&rpos, &rremain, status);
+ if (!ok) {
+ goto fail;
+ }
+
+ ok = psasim_serialise_buffer(&rpos, &rremain, data, data_size);
+ if (!ok) {
+ goto fail;
+ }
+
+ ok = psasim_serialise_size_t(&rpos, &rremain, data_length);
+ if (!ok) {
+ goto fail;
+ }
+
+ *out_params = result;
+ *out_params_len = result_size;
+
+ free(data);
+
+ return 1; // success
+
+fail:
+ free(result);
+
+ free(data);
+
+ return 0; // This shouldn't happen!
+}
+
+// Returns 1 for success, 0 for failure
+int psa_export_public_key_wrapper(
+ uint8_t *in_params, size_t in_params_len,
+ uint8_t **out_params, size_t *out_params_len)
+{
+ psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+ mbedtls_svc_key_id_t key;
+ uint8_t *data = NULL;
+ size_t data_size;
+ size_t data_length;
+
+ uint8_t *pos = in_params;
+ size_t remaining = in_params_len;
+ uint8_t *result = NULL;
+ int ok;
+
+ ok = psasim_deserialise_begin(&pos, &remaining);
+ if (!ok) {
+ goto fail;
+ }
+
+ ok = psasim_deserialise_mbedtls_svc_key_id_t(&pos, &remaining, &key);
+ if (!ok) {
+ goto fail;
+ }
+
+ ok = psasim_deserialise_buffer(&pos, &remaining, &data, &data_size);
+ if (!ok) {
+ goto fail;
+ }
+
+ ok = psasim_deserialise_size_t(&pos, &remaining, &data_length);
+ if (!ok) {
+ goto fail;
+ }
+
+ // Now we call the actual target function
+
+ status = psa_export_public_key(
+ key,
+ data, data_size,
+ &data_length
+ );
+
+ // NOTE: Should really check there is no overflow as we go along.
+ size_t result_size =
+ psasim_serialise_begin_needs() +
+ psasim_serialise_psa_status_t_needs(status) +
+ psasim_serialise_buffer_needs(data, data_size) +
+ psasim_serialise_size_t_needs(data_length);
+
+ result = malloc(result_size);
+ if (result == NULL) {
+ goto fail;
+ }
+
+ uint8_t *rpos = result;
+ size_t rremain = result_size;
+
+ ok = psasim_serialise_begin(&rpos, &rremain);
+ if (!ok) {
+ goto fail;
+ }
+
+ ok = psasim_serialise_psa_status_t(&rpos, &rremain, status);
+ if (!ok) {
+ goto fail;
+ }
+
+ ok = psasim_serialise_buffer(&rpos, &rremain, data, data_size);
+ if (!ok) {
+ goto fail;
+ }
+
+ ok = psasim_serialise_size_t(&rpos, &rremain, data_length);
+ if (!ok) {
+ goto fail;
+ }
+
+ *out_params = result;
+ *out_params_len = result_size;
+
+ free(data);
+
+ return 1; // success
+
+fail:
+ free(result);
+
+ free(data);
+
+ return 0; // This shouldn't happen!
+}
+
+// Returns 1 for success, 0 for failure
int psa_generate_key_wrapper(
uint8_t *in_params, size_t in_params_len,
uint8_t **out_params, size_t *out_params_len)
@@ -5112,6 +5300,69 @@
}
// Returns 1 for success, 0 for failure
+int psa_purge_key_wrapper(
+ uint8_t *in_params, size_t in_params_len,
+ uint8_t **out_params, size_t *out_params_len)
+{
+ psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+ mbedtls_svc_key_id_t key;
+
+ uint8_t *pos = in_params;
+ size_t remaining = in_params_len;
+ uint8_t *result = NULL;
+ int ok;
+
+ ok = psasim_deserialise_begin(&pos, &remaining);
+ if (!ok) {
+ goto fail;
+ }
+
+ ok = psasim_deserialise_mbedtls_svc_key_id_t(&pos, &remaining, &key);
+ if (!ok) {
+ goto fail;
+ }
+
+ // Now we call the actual target function
+
+ status = psa_purge_key(
+ key
+ );
+
+ // NOTE: Should really check there is no overflow as we go along.
+ size_t result_size =
+ psasim_serialise_begin_needs() +
+ psasim_serialise_psa_status_t_needs(status);
+
+ result = malloc(result_size);
+ if (result == NULL) {
+ goto fail;
+ }
+
+ uint8_t *rpos = result;
+ size_t rremain = result_size;
+
+ ok = psasim_serialise_begin(&rpos, &rremain);
+ if (!ok) {
+ goto fail;
+ }
+
+ ok = psasim_serialise_psa_status_t(&rpos, &rremain, status);
+ if (!ok) {
+ goto fail;
+ }
+
+ *out_params = result;
+ *out_params_len = result_size;
+
+ return 1; // success
+
+fail:
+ free(result);
+
+ return 0; // This shouldn't happen!
+}
+
+// Returns 1 for success, 0 for failure
int psa_raw_key_agreement_wrapper(
uint8_t *in_params, size_t in_params_len,
uint8_t **out_params, size_t *out_params_len)
@@ -5764,6 +6015,14 @@
ok = psa_destroy_key_wrapper(in_params, in_params_len,
&out_params, &out_params_len);
break;
+ case PSA_EXPORT_KEY:
+ ok = psa_export_key_wrapper(in_params, in_params_len,
+ &out_params, &out_params_len);
+ break;
+ case PSA_EXPORT_PUBLIC_KEY:
+ ok = psa_export_public_key_wrapper(in_params, in_params_len,
+ &out_params, &out_params_len);
+ break;
case PSA_GENERATE_KEY:
ok = psa_generate_key_wrapper(in_params, in_params_len,
&out_params, &out_params_len);
@@ -5892,6 +6151,10 @@
ok = psa_mac_verify_setup_wrapper(in_params, in_params_len,
&out_params, &out_params_len);
break;
+ case PSA_PURGE_KEY:
+ ok = psa_purge_key_wrapper(in_params, in_params_len,
+ &out_params, &out_params_len);
+ break;
case PSA_RAW_KEY_AGREEMENT:
ok = psa_raw_key_agreement_wrapper(in_params, in_params_len,
&out_params, &out_params_len);
diff --git a/tests/psa-client-server/psasim/src/psa_sim_generate.pl b/tests/psa-client-server/psasim/src/psa_sim_generate.pl
index 82a6249..1c27487 100755
--- a/tests/psa-client-server/psasim/src/psa_sim_generate.pl
+++ b/tests/psa-client-server/psasim/src/psa_sim_generate.pl
@@ -4646,3 +4646,194 @@
uint8_t *output,
size_t output_size,
size_t *output_length);
+
+/** Remove non-essential copies of key material from memory.
+ *
+ * If the key identifier designates a volatile key, this functions does not do
+ * anything and returns successfully.
+ *
+ * If the key identifier designates a persistent key, then this function will
+ * free all resources associated with the key in volatile memory. The key
+ * data in persistent storage is not affected and the key can still be used.
+ *
+ * \param key Identifier of the key to purge.
+ *
+ * \retval #PSA_SUCCESS
+ * The key material will have been removed from memory if it is not
+ * currently required.
+ * \retval #PSA_ERROR_INVALID_ARGUMENT
+ * \p key is not a valid key identifier.
+ * \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_purge_key(mbedtls_svc_key_id_t key);
+
+/**
+ * \brief Export a key in binary format.
+ *
+ * The output of this function can be passed to psa_import_key() to
+ * create an equivalent object.
+ *
+ * If the implementation of psa_import_key() supports other formats
+ * beyond the format specified here, the output from psa_export_key()
+ * must use the representation specified here, not the original
+ * representation.
+ *
+ * For standard key types, the output format is as follows:
+ *
+ * - For symmetric keys (including MAC keys), the format is the
+ * raw bytes of the key.
+ * - For DES, the key data consists of 8 bytes. The parity bits must be
+ * correct.
+ * - For Triple-DES, the format is the concatenation of the
+ * two or three DES keys.
+ * - For RSA key pairs (#PSA_KEY_TYPE_RSA_KEY_PAIR), the format
+ * is the non-encrypted DER encoding of the representation defined by
+ * PKCS\#1 (RFC 8017) as `RSAPrivateKey`, version 0.
+ * ```
+ * RSAPrivateKey ::= SEQUENCE {
+ * version INTEGER, -- must be 0
+ * modulus INTEGER, -- n
+ * publicExponent INTEGER, -- e
+ * privateExponent INTEGER, -- d
+ * prime1 INTEGER, -- p
+ * prime2 INTEGER, -- q
+ * exponent1 INTEGER, -- d mod (p-1)
+ * exponent2 INTEGER, -- d mod (q-1)
+ * coefficient INTEGER, -- (inverse of q) mod p
+ * }
+ * ```
+ * - For elliptic curve key pairs (key types for which
+ * #PSA_KEY_TYPE_IS_ECC_KEY_PAIR is true), the format is
+ * a representation of the private value as a `ceiling(m/8)`-byte string
+ * where `m` is the bit size associated with the curve, i.e. the bit size
+ * of the order of the curve's coordinate field. This byte string is
+ * in little-endian order for Montgomery curves (curve types
+ * `PSA_ECC_FAMILY_CURVEXXX`), and in big-endian order for Weierstrass
+ * curves (curve types `PSA_ECC_FAMILY_SECTXXX`, `PSA_ECC_FAMILY_SECPXXX`
+ * and `PSA_ECC_FAMILY_BRAINPOOL_PXXX`).
+ * For Weierstrass curves, this is the content of the `privateKey` field of
+ * the `ECPrivateKey` format defined by RFC 5915. For Montgomery curves,
+ * the format is defined by RFC 7748, and output is masked according to §5.
+ * For twisted Edwards curves, the private key is as defined by RFC 8032
+ * (a 32-byte string for Edwards25519, a 57-byte string for Edwards448).
+ * - For Diffie-Hellman key exchange key pairs (key types for which
+ * #PSA_KEY_TYPE_IS_DH_KEY_PAIR is true), the
+ * format is the representation of the private key `x` as a big-endian byte
+ * string. The length of the byte string is the private key size in bytes
+ * (leading zeroes are not stripped).
+ * - For public keys (key types for which #PSA_KEY_TYPE_IS_PUBLIC_KEY is
+ * true), the format is the same as for psa_export_public_key().
+ *
+ * The policy on the key must have the usage flag #PSA_KEY_USAGE_EXPORT set.
+ *
+ * \param key Identifier of the key to export. It must allow the
+ * usage #PSA_KEY_USAGE_EXPORT, unless it is a public
+ * key.
+ * \param[out] data Buffer where the key data is to be written.
+ * \param data_size Size of the \p data buffer in bytes.
+ * \param[out] data_length On success, the number of bytes
+ * that make up the key data.
+ *
+ * \retval #PSA_SUCCESS \emptydescription
+ * \retval #PSA_ERROR_INVALID_HANDLE \emptydescription
+ * \retval #PSA_ERROR_NOT_PERMITTED
+ * The key does not have the #PSA_KEY_USAGE_EXPORT flag.
+ * \retval #PSA_ERROR_NOT_SUPPORTED \emptydescription
+ * \retval #PSA_ERROR_BUFFER_TOO_SMALL
+ * The size of the \p data buffer is too small. You can determine a
+ * sufficient buffer size by calling
+ * #PSA_EXPORT_KEY_OUTPUT_SIZE(\c type, \c bits)
+ * where \c type is the key type
+ * and \c bits is the key size in bits.
+ * \retval #PSA_ERROR_COMMUNICATION_FAILURE \emptydescription
+ * \retval #PSA_ERROR_HARDWARE_FAILURE \emptydescription
+ * \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription
+ * \retval #PSA_ERROR_STORAGE_FAILURE \emptydescription
+ * \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription
+ * \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_export_key(mbedtls_svc_key_id_t key,
+ uint8_t *data,
+ size_t data_size,
+ size_t *data_length);
+
+/**
+ * \brief Export a public key or the public part of a key pair in binary format.
+ *
+ * The output of this function can be passed to psa_import_key() to
+ * create an object that is equivalent to the public key.
+ *
+ * This specification supports a single format for each key type.
+ * Implementations may support other formats as long as the standard
+ * format is supported. Implementations that support other formats
+ * should ensure that the formats are clearly unambiguous so as to
+ * minimize the risk that an invalid input is accidentally interpreted
+ * according to a different format.
+ *
+ * For standard key types, the output format is as follows:
+ * - For RSA public keys (#PSA_KEY_TYPE_RSA_PUBLIC_KEY), the DER encoding of
+ * the representation defined by RFC 3279 §2.3.1 as `RSAPublicKey`.
+ * ```
+ * RSAPublicKey ::= SEQUENCE {
+ * modulus INTEGER, -- n
+ * publicExponent INTEGER } -- e
+ * ```
+ * - For elliptic curve keys on a twisted Edwards curve (key types for which
+ * #PSA_KEY_TYPE_IS_ECC_PUBLIC_KEY is true and #PSA_KEY_TYPE_ECC_GET_FAMILY
+ * returns #PSA_ECC_FAMILY_TWISTED_EDWARDS), the public key is as defined
+ * by RFC 8032
+ * (a 32-byte string for Edwards25519, a 57-byte string for Edwards448).
+ * - For other elliptic curve public keys (key types for which
+ * #PSA_KEY_TYPE_IS_ECC_PUBLIC_KEY is true), the format is the uncompressed
+ * representation defined by SEC1 §2.3.3 as the content of an ECPoint.
+ * Let `m` be the bit size associated with the curve, i.e. the bit size of
+ * `q` for a curve over `F_q`. The representation consists of:
+ * - The byte 0x04;
+ * - `x_P` as a `ceiling(m/8)`-byte string, big-endian;
+ * - `y_P` as a `ceiling(m/8)`-byte string, big-endian.
+ * - For Diffie-Hellman key exchange public keys (key types for which
+ * #PSA_KEY_TYPE_IS_DH_PUBLIC_KEY is true),
+ * the format is the representation of the public key `y = g^x mod p` as a
+ * big-endian byte string. The length of the byte string is the length of the
+ * base prime `p` in bytes.
+ *
+ * Exporting a public key object or the public part of a key pair is
+ * always permitted, regardless of the key's usage flags.
+ *
+ * \param key Identifier of the key to export.
+ * \param[out] data Buffer where the key data is to be written.
+ * \param data_size Size of the \p data buffer in bytes.
+ * \param[out] data_length On success, the number of bytes
+ * that make up the key data.
+ *
+ * \retval #PSA_SUCCESS \emptydescription
+ * \retval #PSA_ERROR_INVALID_HANDLE \emptydescription
+ * \retval #PSA_ERROR_INVALID_ARGUMENT
+ * The key is neither a public key nor a key pair.
+ * \retval #PSA_ERROR_NOT_SUPPORTED \emptydescription
+ * \retval #PSA_ERROR_BUFFER_TOO_SMALL
+ * The size of the \p data buffer is too small. You can determine a
+ * sufficient buffer size by calling
+ * #PSA_EXPORT_KEY_OUTPUT_SIZE(#PSA_KEY_TYPE_PUBLIC_KEY_OF_KEY_PAIR(\c type), \c bits)
+ * where \c type is the key type
+ * and \c bits is the key size in bits.
+ * \retval #PSA_ERROR_COMMUNICATION_FAILURE \emptydescription
+ * \retval #PSA_ERROR_HARDWARE_FAILURE \emptydescription
+ * \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription
+ * \retval #PSA_ERROR_STORAGE_FAILURE \emptydescription
+ * \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription
+ * \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_export_public_key(mbedtls_svc_key_id_t key,
+ uint8_t *data,
+ size_t data_size,
+ size_t *data_length);