psasim: add support for key functions that don't need psa_key_attributes_t

Signed-off-by: Tom Cosgrove <tom.cosgrove@arm.com>
This commit is contained in:
Tom Cosgrove 2024-06-21 16:26:03 +01:00 committed by Valerio Setti
parent 8f1c913e38
commit 1a8b805cf5
4 changed files with 675 additions and 0 deletions

View File

@ -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,

View File

@ -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,

View File

@ -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);

View File

@ -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 &sect;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 &sect;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);