-
Notifications
You must be signed in to change notification settings - Fork 27
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Part of moving Parsec to use psa-crypto #28
Conversation
Signed-off-by: Samuel Bailey <samuel.bailey@arm.com>
…n. Moved some error consts over from bnding. Signed-off-by: Samuel Bailey <samuel.bailey@arm.com>
…se key handle closing error. Signed-off-by: Samuel Bailey <samuel.bailey@arm.com>
Signed-off-by: Samuel Bailey <samuel.bailey@arm.com>
Signed-off-by: Samuel Bailey <samuel.bailey@arm.com>
Signed-off-by: Samuel Bailey <samuel.bailey@arm.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for this PR! This is very good overall, thanks for taking the time to fix the issue, add examples and tests.
I made a few comments we can always discuss!
psa-crypto-sys/src/constants.rs
Outdated
pub const PSA_KEY_SLOT_COUNT: isize = 32; | ||
pub const PSA_MAX_PERSISTENT_KEY_IDENTIFIER: psa_key_id_t = 0x3fff_ffff; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These values seem to be Mbed Crypto specific. Ideally this crate is common to all PSA Crypto implementation so it would be better, I think, to declare those values in the code that needs them directly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, they are Mbed Crypto specific. Should they be moved to parsec?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes I think it will be better.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Presumably PSA_MAX_PERSISTENT_KEY_IDENTIFIER
will be replaced with something else in PSA Crypto 1.0?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Presumably PSA_MAX_PERSISTENT_KEY_IDENTIFIER will be replaced with something else in PSA Crypto 1.0?
That's a good point, on section 9.1.1, for psa_key_id_t
, it defines ranges of key identifiers. For example for application key identifiers, it can range from PSA_KEY_ID_USER_MIN
(0x00000001
) to PSA_KEY_ID_USER_MAX
(0x3fffffff
). Which is the same value as the one above 😄! So I guess as PSA_KEY_SLOT_COUNT
should be removed, PSA_MAX_PERSISTENT_KEY_IDENTIFIER
can be renamed to PSA_KEY_ID_USER_MAX
psa-crypto-sys/src/lib.rs
Outdated
psa_close_key, psa_crypto_init, psa_destroy_key, psa_export_public_key, psa_generate_key, | ||
psa_import_key, psa_key_attributes_t, psa_open_key, psa_reset_key_attributes, psa_sign_hash, | ||
psa_verify_hash, | ||
mbedtls_psa_crypto_free, psa_close_key, psa_crypto_init, psa_destroy_key, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same for mbedtls_psa_crypto_free
, I don't think we should declare it here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure how we should deal with this. For psa-crypto
to be portable to any PSA Crypto implementation, we can't have this mbedtls
specific method declared here, but I'm not sure how we remove it from psa-crypto
and allow Parsec to call it without binding straight through to mbedtls
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is is used inside Mbed Crypto for testing but should not be required in this crate. If it is, and creating leaks in our applications, we should probably discuss this at a PSA Crypto level.
|
||
pub fn get_key_attributes(key: Id) -> Result<Attributes> { | ||
initialized()?; | ||
let mut key_attributes = unsafe { psa_crypto_sys::psa_key_attributes_init() }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think if we follow the specs, the attributes created here might allocate some extra space that needs to be freed with a call to psa_reset_key_attributes
(Attributes::reset
). I think that might be needed on every path leaving the function once psa_key_attributes_init
has been called.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hence my pet peeve with these cleanup methods.
What happens if both close_handle
and psa_reset_key_attributes
fail, which value do we return? Maybe we should really return a generic error when some of these "internal" methods fail, that the user should not really know about.
An alternative would be to make a "layered" function, where for each variable that needs cleaning up we wrap everything after it in a function that returns a Result
. If the result is Ok
, attempt to clean up and if that fails return an error, otherwise return the Ok
you got. If what you got was Err
, then do the clean up anyway and return the Err
you got from the next layer function. If you have two things that you need to clean, unfortunately you'd have 2 "layer" functions. But the benefit is that you're sure that you clean up everything and you return the Err
that's most appropriate.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think psa_reset_key_attributes
can't fail, though that doesn't invalidate the general point, just that particular example!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Also, I think you don't need to call psa_reset_key_attributes
if calling psa_key_attributes_init
is all you've done with the psa_key_attributes_t
, and according to the 1.0 spec there seem to be certain psa_set_key_
functions that you can call without needing to do the reset.)
if key_lifetime != Lifetime::Volatile { | ||
Status::from(unsafe { psa_crypto_sys::psa_close_key(handle) }).to_result()?; | ||
} | ||
operation_result?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you think that if psa_generate_key
or psa_import_key
failed you still need to close the key? I would have thought that if those operations fail, they do not open the key.
The documentation of psa_generate_key
says:
* \param[out] handle On success, a handle to the newly created key.
* \c 0 on failure.
So I think this is fine not passing operation_result
to this function (checking in the caller if it failed or not).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have checked psa_generate_key
and psa_import_key
- you are correct, a handle should not be created unless the operation succeeds.
psa-crypto/src/types/key.rs
Outdated
@@ -12,6 +12,9 @@ use crate::types::status::{Error, Result}; | |||
#[cfg(feature = "with-mbed-crypto")] | |||
use core::convert::{TryFrom, TryInto}; | |||
use log::error; | |||
pub use psa_crypto_sys::{ | |||
psa_key_id_t as key_id_type, PSA_KEY_SLOT_COUNT, PSA_MAX_PERSISTENT_KEY_IDENTIFIER, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the renaming of psa_key_id_t
required? I think it is easier to understand when you have the original type name but that might be a personal opinion 😋
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, not required. I think I just did it so it was clear in my head when I was making the change, so I didn't trip up with the other reference to the same type from the binding, when I was swapping them over. I agree, it'll be clearer if the original name is kept 😃
psa-crypto/src/types/status.rs
Outdated
// Commented out as all errors are currently matched against and this causes compilation error | ||
/*e => { | ||
error!("No equivalent of {:?} to a psa_status_t.", e); | ||
psa_crypto_sys::PSA_ERROR_GENERIC_ERROR | ||
} | ||
}*/ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's great, thanks for completing this conversion. Feel free to delete that block altogether 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will remove
use psa_crypto::types::key::{Attributes, Lifetime, Policy, Type, UsageFlags}; | ||
|
||
#[test] | ||
fn generate_integration_test() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice, thanks for the new integration tests!
Nice to see that the CI passed them as well!
key.close_handle(handle)?; | ||
|
||
sign_res?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That is actually quite clever 😄 Never thought of doing it like that before.
/// let key_attributes = key_management::get_key_attributes(my_key); | ||
/// ``` | ||
|
||
pub fn get_key_attributes(key: Id) -> Result<Attributes> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In a way, this function is a contructor of Attributes
so I think it could be placed inside the impl Attributes
block. In that case, we could rename it, using namespacing. What about something like from_key
? It would then be Attributes::from_key(...)
to invoke it.
Agree that we would deviate from the PSA Crypto naming but I think it is fine if we make it more Rust-like!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
from_key_id
- Id
is not a key per se and we keep naming things as if it is.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for the changes! 👍
|
||
.to_result(); | ||
key.close_handle(handle)?; | ||
|
||
sign_res?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For these cases where you need to do a cleanup operation that may fail (after some other core operation might've failed in the first place) we have to decide: if both fail, which error do we want to be returned? I'd say the error on the "core" operation should take precedence, in which case the two branches (as in, if the core operation failed or not) will be different
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, I wish we had a better approach to this kind of problem where you have some cleanup to do whenever you exit the function. In this case it's fine since there's not much branching, but in some cases it might end up being a pain having to call that close_handle
for each possible path before doing ?
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I originally had it returning the first operation error, then the close handle error but after a brief discussion with @hug-dev, it was changed to how it is now. I think the reason was the PSA API states keys aren't used, IDs are, so it should be getting removed at some point (soon? 😄) anyway.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I think that makes sense for this case, my comment was more general - we should have a statement somewhere as to how to prioritize these errors throughout the library. I'd even say that this applies to Parsec too. The last error to occur is not necessarily the one we should return.
/// let key_attributes = key_management::get_key_attributes(my_key); | ||
/// ``` | ||
|
||
pub fn get_key_attributes(key: Id) -> Result<Attributes> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
from_key_id
- Id
is not a key per se and we keep naming things as if it is.
|
||
pub fn get_key_attributes(key: Id) -> Result<Attributes> { | ||
initialized()?; | ||
let mut key_attributes = unsafe { psa_crypto_sys::psa_key_attributes_init() }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hence my pet peeve with these cleanup methods.
What happens if both close_handle
and psa_reset_key_attributes
fail, which value do we return? Maybe we should really return a generic error when some of these "internal" methods fail, that the user should not really know about.
An alternative would be to make a "layered" function, where for each variable that needs cleaning up we wrap everything after it in a function that returns a Result
. If the result is Ok
, attempt to clean up and if that fails return an error, otherwise return the Ok
you got. If what you got was Err
, then do the clean up anyway and return the Err
you got from the next layer function. If you have two things that you need to clean, unfortunately you'd have 2 "layer" functions. But the benefit is that you're sure that you clean up everything and you return the Err
that's most appropriate.
Disregard the approval for now, my mistake 😅 |
psa-crypto-sys/src/c/shim.h
Outdated
@@ -83,6 +83,7 @@ psa_algorithm_t shim_get_key_algorithm(const psa_key_attributes_t *attributes); | |||
psa_key_usage_t | |||
shim_get_key_usage_flags(const psa_key_attributes_t *attributes); | |||
psa_key_attributes_t shim_key_attributes_init(void); | |||
psa_status_t shim_get_key_attributes(psa_key_handle_t key_handle, psa_key_attributes_t *attributes); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be nice to tidy this code up a bit while you're at it. How about having the return type consistently on the same line as the function name and putting the functions in alphabetical order as they already mostly are?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it possible to add CI linting (potentially clang-format
)? Wouldn't take care of the alphabetical order, but it would keep other things tidy. Might be a bit overkill, tho
psa-crypto-sys/src/constants.rs
Outdated
@@ -25,6 +25,9 @@ pub const PSA_ERROR_HARDWARE_FAILURE: psa_status_t = -147; | |||
pub const PSA_ERROR_INSUFFICIENT_ENTROPY: psa_status_t = -148; | |||
pub const PSA_ERROR_INVALID_SIGNATURE: psa_status_t = -149; | |||
pub const PSA_ERROR_INVALID_PADDING: psa_status_t = -150; | |||
pub const PSA_ERROR_CORRUPTION_DETECTED: psa_status_t = -151; | |||
pub const PSA_ERROR_DATA_CORRUPT: psa_status_t = -152; | |||
pub const PSA_ERROR_DATA_INVALID: psa_status_t = -153; | |||
pub const PSA_ERROR_INSUFFICIENT_DATA: psa_status_t = -143; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The last two (-143 and -136) seem to be in the wrong place but that's not part of this patch so I shouldn't really complain.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remind me why these values can't come from the C library somehow? In a previous patch we had something like pub const PSA_SOMETHING: psa_something_t = shim_PSA_SOMETHING;
in the Rust code and const psa_something_t shim_PSA_SOMETHING = PSA_SOMETHING;
in shim.h
. It would be nice to explain in a comment at the top of constants.rs
why these values are being repeated like this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We removed from the shim all the values that are defined by the specification. That way, it allows you to use those value, without having to link with a PSA Crypto implementation (that is the implementation-defined
feature). That is useful for Parsec interface where we re-use some of these values but do not want to link to a PSA Crypto implementation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At least I hope I removed all the duplication, as I did everything manually
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I hadn't realised some values are defined by the specification. Should that be mentioned in a comment in constants.rs
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that makes sense - we do have a module comment in this file, it might be worth expanding that to explain the logic of what's hidden by implementation-defined
- there's a brief explanation here but it should really be in docs.rs too.
psa-crypto-sys/src/constants.rs
Outdated
pub const PSA_KEY_SLOT_COUNT: isize = 32; | ||
pub const PSA_MAX_PERSISTENT_KEY_IDENTIFIER: psa_key_id_t = 0x3fff_ffff; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Presumably PSA_MAX_PERSISTENT_KEY_IDENTIFIER
will be replaced with something else in PSA Crypto 1.0?
|
||
pub fn get_key_attributes(key: Id) -> Result<Attributes> { | ||
initialized()?; | ||
let mut key_attributes = unsafe { psa_crypto_sys::psa_key_attributes_init() }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think psa_reset_key_attributes
can't fail, though that doesn't invalidate the general point, just that particular example!
|
||
pub fn get_key_attributes(key: Id) -> Result<Attributes> { | ||
initialized()?; | ||
let mut key_attributes = unsafe { psa_crypto_sys::psa_key_attributes_init() }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Also, I think you don't need to call psa_reset_key_attributes
if calling psa_key_attributes_init
is all you've done with the psa_key_attributes_t
, and according to the 1.0 spec there seem to be certain psa_set_key_
functions that you can call without needing to do the reset.)
Signed-off-by: Samuel Bailey <samuel.bailey@arm.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One small last comment but otherwise it looks good for me!
psa-crypto/src/lib.rs
Outdated
@@ -43,6 +43,7 @@ | |||
|
|||
#[cfg(feature = "with-mbed-crypto")] | |||
pub mod operations; | |||
#[cfg(feature = "with-mbed-crypto")] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this cfg
gate is needed for that module!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For types
? Now get_key_attributes
is in Attributes
, it needs access to some mbed-crypto
specific code (as in, other code behind the cfg
gate, like initialized
, psa_key_attributes_ini()
, etc). Without that, ci.sh
gives a load of not found in
errors.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, I could make it more local. Adding a gate for use crate::initialized
and one for the method.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm ok with the changes as they are! Leaving it to @hug-dev if he thinks any more changes are needed
/// //... | ||
/// let key_attributes = Attributes::from_key_id(my_key_id); | ||
/// ``` | ||
pub fn from_key_id(key_id: Id) -> Result<Self> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it be worth having a test for this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As there is an example, let's say it is fine for now but think about adding one in the future 🤡
Make feature gate for Attributes::from_key_id more local Tidy up and organise function and constant declarations Re-add ID min and max range values Signed-off-by: Samuel Bailey <samuel.bailey@arm.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me! Thanks for all the changes
…ultaneously Signed-off-by: Samuel Bailey <samuel.bailey@arm.com>
Part of Parsec Issue #177
Includes #26
Contains changes required to allow Prasec to use
psa-crypto
instead of binding directly tombedtls
.