Key wrapping API proposal #364

Open
gilles-peskine-arm wants to merge 8 commits from gilles-peskine-arm/psa-wrap-api into development
gilles-peskine-arm commented 2020-02-10 08:37:15 -06:00 (Migrated from github.com)

This is a first draft of the key wrapping API for PSA Cryptography 1.x.

This pull request only provides function prototypes and associated macro definitions. Tests and implementations will come later.

I implemented the proposal discussed in private. I'm not attached to function/macro names if you have better suggestions. The API comprises:

  • Functions to back up and restore a key, wrapped with another key, using a vendor-chosen algorithm.
  • A reserved identifier value for a wrapping key. There is currently no way to create a wrapping key that can wrap keys with metadata.
  • Functions to wrap key material with another key, using standard algorithms.
This is a first draft of the key wrapping API for PSA Cryptography 1.x. This pull request only provides function prototypes and associated macro definitions. Tests and implementations will come later. I implemented the proposal discussed [in private](https://github.com/ARMmbed/psa-crypto-api/issues/77#issuecomment-582506652). I'm not attached to function/macro names if you have better suggestions. The API comprises: * Functions to back up and restore a key, wrapped with another key, using a vendor-chosen algorithm. * A reserved identifier value for a wrapping key. There is currently no way to create a wrapping key that can wrap keys with metadata. * Functions to wrap key material with another key, using standard algorithms.
yanesca (Migrated from github.com) reviewed 2020-02-10 08:37:15 -06:00
MarcusJGStreets (Migrated from github.com) requested changes 2020-02-10 10:24:43 -06:00
@ -852,7 +854,320 @@ psa_status_t psa_export_public_key(psa_key_handle_t handle,
size_t data_size,
MarcusJGStreets (Migrated from github.com) commented 2020-02-10 10:02:38 -06:00

You have used both source key and \p data which I believe both refer to the key to unwrap.
I would prefer consistency as it is quite hard to understand.

You have used both source key and \p data which I believe both refer to the key to unwrap. I would prefer consistency as it is quite hard to understand.
MarcusJGStreets (Migrated from github.com) commented 2020-02-10 10:06:38 -06:00

I believe that from this description the caller must set attributes -> location.
So the caller needs to call psa_get_wrapped_key_attributes

Is there a reason why they should not be able to leave it unset and use the one in the wrapped key?
And potentiall not offer psa_get_wrapped_key_attributes?

I believe that from this description the caller must set attributes -> location. So the caller needs to call psa_get_wrapped_key_attributes Is there a reason why they should not be able to leave it unset and use the one in the wrapped key? And potentiall not offer psa_get_wrapped_key_attributes?
MarcusJGStreets (Migrated from github.com) commented 2020-02-10 10:21:30 -06:00

Is it worth adding a line checking if the copy permission is set.

Is it worth adding a line checking if the copy permission is set.
gilles-peskine-arm (Migrated from github.com) reviewed 2020-02-10 11:53:50 -06:00
@ -852,7 +854,320 @@ psa_status_t psa_export_public_key(psa_key_handle_t handle,
size_t data_size,
gilles-peskine-arm (Migrated from github.com) commented 2020-02-10 11:53:49 -06:00

fixed

fixed
gilles-peskine-arm (Migrated from github.com) reviewed 2020-02-10 11:57:14 -06:00
@ -852,7 +854,320 @@ psa_status_t psa_export_public_key(psa_key_handle_t handle,
size_t data_size,
gilles-peskine-arm (Migrated from github.com) commented 2020-02-10 11:57:14 -06:00

I'd prefer not to have psa_get_wrapped_key_attributes, but I added it because I couldn't find a better way.

“Leave unset” works for the key type and the key size because for those 0 is not a valid value, so it's interpreted as unset. But for lifetimes, 0 is a valid value, indicating a volatile key: keys are volatile by default, you only need to specify a lifetime explicitly if you want the key to live longer. If a wrapped key is non-copyable and persistent, attempting to unwrap it as volatile should fail.

Likewise, for the policy, 0 means “you can't do anything”. That's not the same thing as “use whatever is in the wrapped data”.

I'd prefer not to have `psa_get_wrapped_key_attributes`, but I added it because I couldn't find a better way. “Leave unset” works for the key type and the key size because for those 0 is not a valid value, so it's interpreted as unset. But for lifetimes, 0 is a valid value, indicating a volatile key: keys are volatile by default, you only need to specify a lifetime explicitly if you want the key to live longer. If a wrapped key is non-copyable and persistent, attempting to unwrap it as volatile should fail. Likewise, for the policy, 0 means “you can't do anything”. That's not the same thing as “use whatever is in the wrapped data”.
gilles-peskine-arm (Migrated from github.com) reviewed 2020-02-10 11:58:58 -06:00
@ -852,7 +854,320 @@ psa_status_t psa_export_public_key(psa_key_handle_t handle,
size_t data_size,
gilles-peskine-arm (Migrated from github.com) commented 2020-02-10 11:58:58 -06:00

Why would the calling code check the copy permission? I'd expect typical application code to either expect a copyable key and specify a location here, or not expect a copyable key and not specify the location. Neither case calls for checking the copy permission in the application code.

Why would the calling code check the copy permission? I'd expect typical application code to either expect a copyable key and specify a location here, or not expect a copyable key and not specify the location. Neither case calls for checking the copy permission in the application code.
MarcusJGStreets (Migrated from github.com) reviewed 2020-02-10 12:19:15 -06:00
@ -852,7 +854,320 @@ psa_status_t psa_export_public_key(psa_key_handle_t handle,
size_t data_size,
MarcusJGStreets (Migrated from github.com) commented 2020-02-10 12:19:14 -06:00

Ok - good answer.

Ok - good answer.
MarcusJGStreets (Migrated from github.com) reviewed 2020-02-10 12:19:39 -06:00
@ -852,7 +854,320 @@ psa_status_t psa_export_public_key(psa_key_handle_t handle,
size_t data_size,
MarcusJGStreets (Migrated from github.com) commented 2020-02-10 12:19:39 -06:00

Thanks

Thanks
MarcusJGStreets (Migrated from github.com) reviewed 2020-02-10 12:22:06 -06:00
@ -852,7 +854,320 @@ psa_status_t psa_export_public_key(psa_key_handle_t handle,
size_t data_size,
MarcusJGStreets (Migrated from github.com) commented 2020-02-10 12:22:06 -06:00

Yes you are probably right for IOT.

Yes you are probably right for IOT.
MarcusJGStreets (Migrated from github.com) reviewed 2020-02-10 12:23:17 -06:00
MarcusJGStreets (Migrated from github.com) left a comment
No description provided.
Apporved follwing discussion with giles
athoelke (Migrated from github.com) reviewed 2020-02-10 17:48:17 -06:00
@ -852,7 +854,320 @@ psa_status_t psa_export_public_key(psa_key_handle_t handle,
size_t data_size,
athoelke (Migrated from github.com) commented 2020-02-10 17:48:17 -06:00

Good use cases. How about one or moe of these options as alternatives:

  • Permit attributes == NULL - this indicates that the key should be unwrapped exactly as it was wrapped. No override attributes.
  • Define a special lifetime value to mean ANY - i.e. "as wrapped"
  • Permit usage flags of MAX_UINT32 - and rely on the 'constrain to wrapped key policy' behaviour to replicate the wrapped key usage flags in the unwrapped key.
Good use cases. How about one or moe of these options as alternatives: * Permit `attributes == NULL` - this indicates that the key should be unwrapped exactly as it was wrapped. No override attributes. * Define a special lifetime value to mean `ANY` - i.e. "as wrapped" * Permit usage flags of MAX_UINT32 - and rely on the 'constrain to wrapped key policy' behaviour to replicate the wrapped key usage flags in the unwrapped key.
athoelke (Migrated from github.com) reviewed 2020-02-10 17:56:36 -06:00
@ -1609,0 +1666,4 @@
*
* A wrapped form does not preserve the key metadata in general, so it is up
* to the application to ensure that the key is unwrapped with the correct
* type and policy.
athoelke (Migrated from github.com) commented 2020-02-10 17:56:36 -06:00

Is there any particular significance to the value chosen? - why MIN_UINT32 + 0x62?

Is there any particular significance to the value chosen? - why MIN_UINT32 + 0x62?
athoelke commented 2020-02-10 18:20:51 -06:00 (Migrated from github.com)

Do we also need a usage flag for WRAP and UNWRAP, as well as the defined flags for a key being exporting in wrapped form? Keys used as wrapping keys in psa_wrap_key_*() or psa_unwrap_key_*() would then require the applicable usage flag.

Do we also need a usage flag for WRAP and UNWRAP, as well as the defined flags for a key being exporting in wrapped form? Keys used as wrapping keys in `psa_wrap_key_*()` or `psa_unwrap_key_*()` would then require the applicable usage flag.
athoelke (Migrated from github.com) reviewed 2020-02-10 18:37:43 -06:00
athoelke (Migrated from github.com) left a comment

A few corrections and comments

A few corrections and comments
@ -852,7 +854,320 @@ psa_status_t psa_export_public_key(psa_key_handle_t handle,
size_t data_size,
athoelke (Migrated from github.com) commented 2020-02-10 18:26:32 -06:00

There is no metadata in data for this API.

There is no metadata in `data` for this API.
@ -856,0 +1086,4 @@
* by \p handle.
* \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
athoelke (Migrated from github.com) commented 2020-02-10 18:23:37 -06:00

copy-pasta: presume PSA_KEY_USAGE_EXPORT_WRAPPED

copy-pasta: presume `PSA_KEY_USAGE_EXPORT_WRAPPED`
@ -1082,6 +1094,24 @@
PSA_ALG_AEAD_WITH_TAG_LENGTH(ref, 0) ? \
athoelke (Migrated from github.com) commented 2020-02-10 18:29:54 -06:00

This does not satisfy PSA_ALG_IS_KEY_WRAP() - the category should be 0x0e000000?

This does not satisfy `PSA_ALG_IS_KEY_WRAP()` - the category should be `0x0e000000`?
athoelke (Migrated from github.com) commented 2020-02-10 18:30:25 -06:00

This does not satisfy PSA_ALG_IS_KEY_WRAP() - the category should be 0x0e000000?

This does not satisfy `PSA_ALG_IS_KEY_WRAP()` - the category should be `0x0e000000`?
@ -1609,0 +1666,4 @@
*
* A wrapped form does not preserve the key metadata in general, so it is up
* to the application to ensure that the key is unwrapped with the correct
* type and policy.
athoelke (Migrated from github.com) commented 2020-02-10 18:31:59 -06:00

Not enamoured with the name, as we haven't used "bound" anywhere else in the API or documentation. Is PSA_KEY_ID_WRAP_BUILT_IN any better, or worse?

Not enamoured with the name, as we haven't used "bound" anywhere else in the API or documentation. Is `PSA_KEY_ID_WRAP_BUILT_IN` any better, or worse?
athoelke (Migrated from github.com) commented 2020-02-10 18:36:29 -06:00

If we used PSA_KEY_ID_WRAP_BOUND then I would be inclined to make this PSA_KEY_USAGE_EXPORT_BOUND or perhaps PSA_KEY_USAGE_WRAP_BOUND.

BACKUP is quite cute, but then we should use 'backup' in the wrap-with-policy API name and the built-in wrap-with-policy binding key to strengthen the association of these API elements.

If we used `PSA_KEY_ID_WRAP_BOUND` then I would be inclined to make this `PSA_KEY_USAGE_EXPORT_BOUND` or perhaps `PSA_KEY_USAGE_WRAP_BOUND`. `BACKUP` is quite cute, but then we should use 'backup' in the wrap-with-policy API name and the built-in wrap-with-policy binding key to strengthen the association of these API elements.
gilles-peskine-arm (Migrated from github.com) reviewed 2020-02-11 04:45:06 -06:00
@ -852,7 +854,320 @@ psa_status_t psa_export_public_key(psa_key_handle_t handle,
size_t data_size,
gilles-peskine-arm (Migrated from github.com) commented 2020-02-11 04:45:06 -06:00

Permit attributes == NULL

Doesn't help if you want to use the wrapped policy but specify a different lifetime or id, which I think is a very common use case.

Permit usage flags of MAX_UINT32

That does in fact work for the usage flags, but not for the algorithm. It could be added as a feature for the algorithm.

> Permit attributes == NULL Doesn't help if you want to use the wrapped policy but specify a different lifetime or id, which I think is a very common use case. > Permit usage flags of MAX_UINT32 That does in fact work for the usage flags, but not for the algorithm. It could be added as a feature for the algorithm.
gilles-peskine-arm (Migrated from github.com) reviewed 2020-02-11 04:47:18 -06:00
@ -1609,0 +1666,4 @@
*
* A wrapped form does not preserve the key metadata in general, so it is up
* to the application to ensure that the key is unwrapped with the correct
* type and policy.
gilles-peskine-arm (Migrated from github.com) commented 2020-02-11 04:47:18 -06:00

0x80000000 is the start of the range reserved for ids defined by PSA.

0x80000000 + 'b' (for “bound”) because why not.

I'm very open to naming suggestions. Once a few people have made theirs I'll do a pass of renaming stuff with an eye to consistency and the other eye to comprehensibility.

0x80000000 is the start of the range reserved for ids defined by PSA. `0x80000000 + 'b'` (for “bound”) because why not. I'm very open to naming suggestions. Once a few people have made theirs I'll do a pass of renaming stuff with an eye to consistency and the other eye to comprehensibility.
athoelke (Migrated from github.com) reviewed 2020-02-11 05:16:44 -06:00
@ -852,7 +854,320 @@ psa_status_t psa_export_public_key(psa_key_handle_t handle,
size_t data_size,
athoelke (Migrated from github.com) commented 2020-02-11 05:16:44 -06:00

The second bullet implies that we define (within the new structured framework) a special lifetime value, e.g.

#define PSA_KEY_LIFETIME_UNSPECIFIED ((psa_key_lifetime_t) 0x0000007f)

This value is only valid in attributes passed to psa_unwrap_key_with_policy() to indicate that the key should be unwrapped into the same lifetime that it was wrapped from.

You could also support all of the above mechanisms:

  1. If you want to restore a backed up key, just pass attributes = NULL. (Volatile keys might have a different key handle/id after unwrapping)
  2. If you want to move the key then initialise the attributes, set the wildcard usage flags (PSA_KEY_USAGE_UNSPECIFIED - all bits 1, not all known bits one: only valid for unwrapping/copying), and set the lifetime/id for the desired location
  3. If you you want to limit the policy, but maintain the lifetime, then initialise the attributes, set the usage flags, and set the lifetime to PSA_KEY_LIFETIME_UNSPECIFIED (only valid for unwrap).

For (1), it would be possible to just use UNSPECIFIED for both the usage flags and the lifetime, but I suspect that the compact attributes = NULL form might be a common usage?

The second bullet implies that we define (within the new structured framework) a special lifetime value, e.g. #define PSA_KEY_LIFETIME_UNSPECIFIED ((psa_key_lifetime_t) 0x0000007f) This value is only valid in attributes passed to `psa_unwrap_key_with_policy()` to indicate that the key should be unwrapped into the same lifetime that it was wrapped from. You could also support all of the above mechanisms: 1. If you want to restore a backed up key, just pass `attributes = NULL`. (Volatile keys might have a different key handle/id after unwrapping) 2. If you want to move the key then initialise the attributes, set the wildcard usage flags (`PSA_KEY_USAGE_UNSPECIFIED` - all bits 1, not all known bits one: only valid for unwrapping/copying), and set the lifetime/id for the desired location 3. If you you want to limit the policy, but maintain the lifetime, then initialise the attributes, set the usage flags, and set the lifetime to `PSA_KEY_LIFETIME_UNSPECIFIED` (only valid for unwrap). For (1), it would be possible to just use `UNSPECIFIED` for both the usage flags and the lifetime, but I suspect that the compact `attributes = NULL` form might be a common usage?
athoelke (Migrated from github.com) reviewed 2020-02-11 05:18:31 -06:00
@ -852,7 +854,320 @@ psa_status_t psa_export_public_key(psa_key_handle_t handle,
size_t data_size,
athoelke (Migrated from github.com) commented 2020-02-11 05:18:31 -06:00

Instead of *_UNSPECIFIED, other terms could be *_AS_SOURCE or *_ORIGINAL.

Instead of `*_UNSPECIFIED`, other terms could be `*_AS_SOURCE` or `*_ORIGINAL`.
gilles-peskine-arm commented 2020-02-12 12:29:56 -06:00 (Migrated from github.com)

@MarcusJGStreets @athoelke I pushed an update with a rewritten history that should resolve all your comments and cover what we discussed orally today, other than the naming. The original version is in https://github.com/gilles-peskine-arm/mbed-crypto/tree/psa-wrap-api-1

  • I fixed copypasta by amending the corresponding commits.
  • I removed the commit that introduced psa_get_wrapped_key_attributes, and instead made a new commit introducing psa_unwrap_key_to_alternate_lifetime and removing the attributes parameter to psa_unwrap_key_with_policy.
  • I added usage flags for wrapping keys.

I'll subsequently make another update to fix the terminology issues (which includes finding a decent name for psa_unwrap_key_to_alternate_lifetime; I couldn't resolve myself to psa_unwrap_key_with_policy_to_alternate_lifetime). I'm more and more warming up to backup/restore for wrap-with-policy. It isn't the only use case for this function (there's also sharing, when another entity has the unwrapping key), but it's a common one. I think anyone would understand backup/restore, even if it isn't what crypto architects would use, unlike “binding”, which even crypto architects don't fully agree on.

@MarcusJGStreets @athoelke I pushed an update with a rewritten history that should resolve all your comments and cover what we discussed orally today, other than the naming. The original version is in https://github.com/gilles-peskine-arm/mbed-crypto/tree/psa-wrap-api-1 * I fixed copypasta by amending the corresponding commits. * I removed the commit that introduced `psa_get_wrapped_key_attributes`, and instead made a new commit introducing `psa_unwrap_key_to_alternate_lifetime` and removing the `attributes` parameter to `psa_unwrap_key_with_policy`. * I added usage flags for wrapping keys. I'll subsequently make another update to fix the terminology issues (which includes finding a decent name for `psa_unwrap_key_to_alternate_lifetime`; I couldn't resolve myself to `psa_unwrap_key_with_policy_to_alternate_lifetime`). I'm more and more warming up to backup/restore for wrap-with-policy. It isn't the only use case for this function (there's also sharing, when another entity has the unwrapping key), but it's a common one. I think anyone would understand backup/restore, even if it isn't what crypto architects would use, unlike “binding”, which even crypto architects don't fully agree on.
athoelke (Migrated from github.com) requested changes 2020-02-12 16:33:21 -06:00
athoelke (Migrated from github.com) left a comment

Still some oopses in the usage flag association with the APIs.

Still some oopses in the usage flag association with the APIs.
@ -855,0 +876,4 @@
* \param handle Handle to the key to export in wrapped form.
* \param[out] data Buffer where the wrapped 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
athoelke (Migrated from github.com) commented 2020-02-12 16:20:20 -06:00

Need to specify which key needs this policy?

Need to specify which key needs this policy?
@ -855,0 +877,4 @@
* \param[out] data Buffer where the wrapped 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 wrapped key data.
athoelke (Migrated from github.com) commented 2020-02-12 16:28:47 -06:00

#PSA_KEY_USAGE_BACKUP for this API

#PSA_KEY_USAGE_BACKUP for this API
@ -856,0 +1086,4 @@
* by \p handle.
* \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
athoelke (Migrated from github.com) commented 2020-02-12 16:29:53 -06:00

This issue is still present.

This issue is still present.
athoelke commented 2020-02-12 16:48:13 -06:00 (Migrated from github.com)

Hi @gilles-peskine-arm - thanks for the update.

  • I'm quite happy with the idea of backup/restore terminology. Would you drop the _material from the other wrapping functions as a result?

  • Some ideas for the tricky-to-name API:

    • psa_restore_key_as_volatile()
    • psa_restore_key_elsewhere() :-)
    • `psa_restore_key_ex()

The usage flag naming gets interesting now that we have "can be wrapped" and "can use to wrap" policy flags. It is clear there are two categories of flags:

  1. Management policies - things the implementation/application can do to a key object: EXPORT, COPY, CACHE, WRAP, BACKUP
  2. Usage policies - things the implementation/application can do with the key material: ENCRYPT, DECRYPT, SIGN, VERIFY, DERIVE, WRAP.

I wonder now if we should have named these categories of flag separately to make it easier to distinguish can-wrap-with from can-be-wrapped.

Hi @gilles-peskine-arm - thanks for the update. * I'm quite happy with the idea of backup/restore terminology. Would you drop the `_material` from the other wrapping functions as a result? * Some ideas for the tricky-to-name API: - `psa_restore_key_as_volatile()` - `psa_restore_key_elsewhere()` :-) - `psa_restore_key_ex() The usage flag naming gets interesting now that we have "can be wrapped" and "can use to wrap" policy flags. It is clear there are two categories of flags: 1. Management policies - things the implementation/application can do **to** a key object: EXPORT, COPY, CACHE, WRAP, BACKUP 2. Usage policies - things the implementation/application can do **with** the key material: ENCRYPT, DECRYPT, SIGN, VERIFY, DERIVE, WRAP. I wonder now if we should have named these categories of flag separately to make it easier to distinguish can-wrap-with from can-be-wrapped.
giacomo3000 (Migrated from github.com) approved these changes 2023-05-06 13:53:36 -05:00
This pull request is broken due to missing fork information.
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin 'gilles-peskine-arm/psa-wrap-api:gilles-peskine-arm/psa-wrap-api'
git switch 'gilles-peskine-arm/psa-wrap-api'

Merge

Merge the changes and update on Forgejo.

Warning: The "Autodetect manual merge" setting is not enabled for this repository, you will have to mark this pull request as manually merged afterwards.

git switch 'development'
git merge --no-ff 'gilles-peskine-arm/psa-wrap-api'
git switch 'gilles-peskine-arm/psa-wrap-api'
git rebase 'development'
git switch 'development'
git merge --ff-only 'gilles-peskine-arm/psa-wrap-api'
git switch 'gilles-peskine-arm/psa-wrap-api'
git rebase 'development'
git switch 'development'
git merge --no-ff 'gilles-peskine-arm/psa-wrap-api'
git switch 'development'
git merge --squash 'gilles-peskine-arm/psa-wrap-api'
git switch 'development'
git merge --ff-only 'gilles-peskine-arm/psa-wrap-api'
git switch 'development'
git merge 'gilles-peskine-arm/psa-wrap-api'
git push origin 'development'
Sign in to join this conversation.
No milestone
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
gh-ARMmbed/mbed-crypto!364
No description provided.