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 fbbdea2db..04401d11b 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 @@ enum { 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 @@ enum { 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 8dd85a317..67a66ff95 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 @@ fail: } +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 @@ fail: } +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 ae803491e..41b4bc651 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 @@ -2414,6 +2414,194 @@ fail: return 0; // This shouldn't happen! } +// 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, @@ -5111,6 +5299,69 @@ fail: return 0; // This shouldn't happen! } +// 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, @@ -5764,6 +6015,14 @@ psa_status_t psa_crypto_call(psa_msg_t msg) 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 @@ psa_status_t psa_crypto_call(psa_msg_t msg) 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 82a6249f3..1c27487b3 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 @@ psa_status_t psa_asymmetric_decrypt(mbedtls_svc_key_id_t key, 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);