Hi experts,
I wanted to forward some crypto operations to an external driver that provides psa_call APIs. The mbedtls version I am using 3.4.0. Take psa_asymmetric_encrypt as an example, The mbedtls api is
psa_status_t psa_asymmetric_encrypt(mbedtls_svc_key_id_t key, psa_algorithm_t alg, const uint8_t *input, size_t input_length, const uint8_t *salt, size_t salt_length, uint8_t *output, size_t output_size, size_t *output_length) It gets attribute, key.data and key.byte from key_id. Then call function psa_driver_wrapper_asymmetric_encrypt without key_id as its argument:
status = psa_driver_wrapper_asymmetric_encrypt( &attributes, slot->key.data, slot->key.bytes, alg, input, input_length, salt, salt_length, output, output_size, output_length);
In psa_driver_wrapper_asymmetric_encrypt, it will use different implementations according to the location value in https://github.com/Mbed-TLS/mbedtls/blob/d69d3cda34c400a55220352518e37d3d2cc....
I define a new location definition(RSS_PSA_LOCATION. When the location is RSS_PSA_LOCATION, making it call
psa_status_t crypto_psa_asymmetric_encrypt(psa_key_id_t key, psa_algorithm_t alg, const uint8_t *input, size_t input_length, const uint8_t *salt, size_t salt_length, uint8_t *output, size_t output_size, size_t *output_length)
This API require key_id. Is it possible to get key_id from attribute and key_slot?
Regards,
Jiamei Xie
Hello,
The function in your driver that implements a function that operates on a key, e.g. the "asymmetric_encrypt", has the following prototype:
psa_status_t my_driver_asymmetric_encrypt(const psa_key_attributes_t *attributes, const uint8_t *key_buffer, size_t key_buffer_size, ...);
(See https://github.com/Mbed-TLS/mbedtls/blob/mbedtls-3.5.0/docs/proposed/psa-dri...)
Your driver can identify the key using the content of key_buffer. For an opaque driver, this can be either the key material in wrapped form (if your secure element doesn't have persistent storage) or an identifier chosen when the key is created (if your secure element keeps the key in its own storage, and you access the key externally through some name or identifier).
If I understand correctly, your secure element (the RSS) happens to implement the PSA API, so you access the key via a persistent key identifier. Then you should use this key identifier as the content of key_buffer.
Please note that in Mbed TLS, managing keys that are stored in a secure element is not ready for production, because it can lead to corruption if there is a power failure (https://github.com/Mbed-TLS/mbedtls/issues/8431). It's ok if you only access existing keys through the PSA API, and use proprietary means to create/destroy the keys.
(Note that this is about keys that are /stored/ in the secure element. There is no problem for keys that can only be used by the secure element, but are stored in a wrapped form outside the secure element.)
Best regards,
Hi Gilles,
Thanks for your reply.
On 2023/10/27 00:36, Gilles Peskine wrote:
Hello,
The function in your driver that implements a function that operates on a key, e.g. the "asymmetric_encrypt", has the following prototype: psa_status_t my_driver_asymmetric_encrypt(const psa_key_attributes_t *attributes, const uint8_t *key_buffer, size_t key_buffer_size, ...); (See https://github.com/Mbed-TLS/mbedtls/blob/mbedtls-3.5.0/docs/proposed/psa-dri...)
Your driver can identify the key using the content of key_buffer. For an opaque driver, this can be either the key material in wrapped form (if your secure element doesn't have persistent storage) or an identifier chosen when the key is created (if your secure element keeps the key in its own storage, and you access the key externally through some name or identifier).
If I understand correctly, your secure element (the RSS) happens to implement the PSA API, so you access the key via a persistent key identifier. Then you should use this key identifier as the content of key_buffer.
Yes. This is exactly my scenario.
If I understand it correctly. The current code https://github.com/Mbed-TLS/mbedtls/blob/mbedtls-3.5.0/library/psa_crypto.c#... doesn't consider the situation where the key buffer is key identifier. 'key_id' is 32-bit and 'key_buffer' is 8-bit. To replace key identifier as the content of key_buffer:
When calling
status = psa_driver_wrapper_asymmetric_encrypt( &attributes, slot->key.data, slot->key.bytes, alg, input, input_length, salt, salt_length, output, output_size, output_length);
It should
1) convert key(a struct with a 32-bit member and optional owner member) to key_buffer(unit_8 * 4)
and make the key_buffer as the input of psa_driver_wrapper_asymmetric_encrypt.
2) covert key_buffer (unit_8 * 4) into key_id (32-bit).
Please correct me if I understand wrong.
Please note that in Mbed TLS, managing keys that are stored in a secure element is not ready for production, because it can lead to corruption if there is a power failure (https://github.com/Mbed-TLS/mbedtls/issues/8431). It's ok if you only access existing keys through the PSA API, and use proprietary means to create/destroy the keys.
(Note that this is about keys that are /stored/ in the secure element. There is no problem for keys that can only be used by the secure element, but are stored in a wrapped form outside the secure element.)
Best regards,
-- Gilles Peskine Mbed TLS developer and PSA Crypto architect
On 25/10/2023 08:47, Jiamei Xie via mbed-tls wrote:
Hi experts,
I wanted to forward some crypto operations to an external driver that provides psa_call APIs. The mbedtls version I am using 3.4.0.
Take psa_asymmetric_encrypt as an example, The mbedtls api is
psa_status_t psa_asymmetric_encrypt(mbedtls_svc_key_id_t key,
psa_algorithm_t alg,
const uint8_t *input,
size_t input_length,
const uint8_t *salt,
size_t salt_length,
uint8_t *output,
size_t output_size,
size_t *output_length)
It gets attribute, key.data and key.byte from key_id. Then call function psa_driver_wrapper_asymmetric_encrypt without key_id as its argument:
status = psa_driver_wrapper_asymmetric_encrypt(
&attributes, slot->key.data, slot->key.bytes,
alg, input, input_length, salt, salt_length,
output, output_size, output_length);
In psa_driver_wrapper_asymmetric_encrypt, it will use different implementations according to the location value in https://github.com/Mbed-TLS/mbedtls/blob/d69d3cda34c400a55220352518e37d3d2cc....
I define a new location definition(RSS_PSA_LOCATION. When the location is RSS_PSA_LOCATION, making it call
psa_status_t crypto_psa_asymmetric_encrypt(psa_key_id_t key,
psa_algorithm_t alg,
const uint8_t *input,
size_t input_length,
const uint8_t *salt,
size_t salt_length,
uint8_t *output,
size_t output_size,
size_t *output_length)
This API require key_id. Is it possible to get key_id from attribute and key_slot?
Regards,
Jiamei Xie
On 30/10/2023 04:10, Jiamei Xie wrote:
Hi Gilles,
Thanks for your reply.
On 2023/10/27 00:36, Gilles Peskine wrote:
Hello,
The function in your driver that implements a function that operates on a key, e.g. the "asymmetric_encrypt", has the following prototype: psa_status_t my_driver_asymmetric_encrypt(const psa_key_attributes_t *attributes, const uint8_t *key_buffer, size_t key_buffer_size, ...); (See https://github.com/Mbed-TLS/mbedtls/blob/mbedtls-3.5.0/docs/proposed/psa-dri...)
Your driver can identify the key using the content of key_buffer. For an opaque driver, this can be either the key material in wrapped form (if your secure element doesn't have persistent storage) or an identifier chosen when the key is created (if your secure element keeps the key in its own storage, and you access the key externally through some name or identifier).
If I understand correctly, your secure element (the RSS) happens to implement the PSA API, so you access the key via a persistent key identifier. Then you should use this key identifier as the content of key_buffer.
Yes. This is exactly my scenario.
If I understand it correctly. The current code https://github.com/Mbed-TLS/mbedtls/blob/mbedtls-3.5.0/library/psa_crypto.c#... doesn't consider the situation where the key buffer is key identifier. 'key_id' is 32-bit and 'key_buffer' is 8-bit. To replace key identifier as the content of key_buffer:
When calling
status = psa_driver_wrapper_asymmetric_encrypt( &attributes, slot->key.data, slot->key.bytes, alg, input, input_length, salt, salt_length, output, output_size, output_length);
It should
- convert key(a struct with a 32-bit member and optional owner
member) to key_buffer(unit_8 * 4)
and make the key_buffer as the input of psa_driver_wrapper_asymmetric_encrypt.
- covert key_buffer (unit_8 * 4) into key_id (32-bit).
Yes. You can use memcpy for that (not a cast, because key_buffer might not be aligned for a uint32_t). That will work unless you want to have persistent keys and read them back on machines with a different endianness.
Best regards,
mbed-tls@lists.trustedfirmware.org