-
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
Changes from 6 commits
19b70b0
3d1580e
d361726
6fd4469
fd73ed1
d539aed
6f34968
2d7b6ae
999187c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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 commentThe 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 commentThe 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 There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 commentThe 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 There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 |
||
pub const PSA_ERROR_INVALID_HANDLE: psa_status_t = -136; | ||
|
||
|
@@ -87,6 +90,8 @@ pub const PSA_KEY_USAGE_DECRYPT: psa_key_usage_t = 512; | |
pub const PSA_KEY_USAGE_SIGN: psa_key_usage_t = 1024; | ||
pub const PSA_KEY_USAGE_VERIFY: psa_key_usage_t = 2048; | ||
pub const PSA_KEY_USAGE_DERIVE: psa_key_usage_t = 4096; | ||
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 commentThe 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 commentThe 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 commentThe 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 commentThe reason will be displayed to describe this comment to others. Learn more. Presumably There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
That's a good point, on section 9.1.1, for |
||
|
||
#[cfg(feature = "implementation-defined")] | ||
pub const PSA_DRV_SE_HAL_VERSION: u32 = 5; |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -39,9 +39,9 @@ pub use types::*; | |
|
||
#[cfg(feature = "implementation-defined")] | ||
pub use psa_crypto_binding::{ | ||
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 commentThe reason will be displayed to describe this comment to others. Learn more. Same for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure how we should deal with this. For There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. |
||
psa_export_public_key, psa_generate_key, psa_get_key_attributes, psa_import_key, | ||
psa_key_attributes_t, psa_open_key, psa_reset_key_attributes, psa_sign_hash, psa_verify_hash, | ||
}; | ||
|
||
// Secure Element Driver definitions | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -64,7 +64,7 @@ pub fn sign_hash( | |
let mut signature_length = 0; | ||
let handle = key.handle()?; | ||
|
||
Status::from(unsafe { | ||
let sign_res = Status::from(unsafe { | ||
psa_crypto_sys::psa_sign_hash( | ||
handle, | ||
alg.into(), | ||
|
@@ -75,10 +75,9 @@ pub fn sign_hash( | |
&mut signature_length, | ||
) | ||
}) | ||
.to_result()?; | ||
|
||
.to_result(); | ||
key.close_handle(handle)?; | ||
|
||
sign_res?; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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.
Comment on lines
-79
to
+80
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 commentThe 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 There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 commentThe 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. |
||
Ok(signature_length) | ||
} | ||
|
||
|
@@ -130,7 +129,7 @@ pub fn verify_hash(key: Id, alg: AsymmetricSignature, hash: &[u8], signature: &[ | |
|
||
let handle = key.handle()?; | ||
|
||
Status::from(unsafe { | ||
let verify_res = Status::from(unsafe { | ||
psa_crypto_sys::psa_verify_hash( | ||
handle, | ||
alg.into(), | ||
|
@@ -140,7 +139,7 @@ pub fn verify_hash(key: Id, alg: AsymmetricSignature, hash: &[u8], signature: &[ | |
signature.len(), | ||
) | ||
}) | ||
.to_result()?; | ||
|
||
key.close_handle(handle) | ||
.to_result(); | ||
key.close_handle(handle)?; | ||
verify_res | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,9 +4,10 @@ | |
//! # Key Management operations | ||
|
||
use crate::initialized; | ||
use crate::types::key::{Attributes, Id}; | ||
use crate::types::key::{Attributes, Id, Lifetime}; | ||
use crate::types::status::{Result, Status}; | ||
use core::convert::TryFrom; | ||
use psa_crypto_sys::{psa_key_handle_t, psa_key_id_t}; | ||
|
||
/// Generate a key or a key pair | ||
/// | ||
|
@@ -47,25 +48,20 @@ use core::convert::TryFrom; | |
/// ``` | ||
pub fn generate(attributes: Attributes, id: Option<u32>) -> Result<Id> { | ||
initialized()?; | ||
|
||
let mut attributes = psa_crypto_sys::psa_key_attributes_t::try_from(attributes)?; | ||
let mut key_attributes = psa_crypto_sys::psa_key_attributes_t::try_from(attributes)?; | ||
let id = if let Some(id) = id { | ||
unsafe { psa_crypto_sys::psa_set_key_id(&mut attributes, id) }; | ||
unsafe { psa_crypto_sys::psa_set_key_id(&mut key_attributes, id) }; | ||
id | ||
} else { | ||
0 | ||
}; | ||
let mut handle = 0; | ||
let gen_res = | ||
Status::from(unsafe { psa_crypto_sys::psa_generate_key(&key_attributes, &mut handle) }) | ||
.to_result(); | ||
Attributes::reset(&mut key_attributes); | ||
|
||
Status::from(unsafe { psa_crypto_sys::psa_generate_key(&attributes, &mut handle) }) | ||
.to_result()?; | ||
|
||
Attributes::reset(&mut attributes); | ||
|
||
Ok(Id { | ||
id, | ||
handle: Some(handle), | ||
}) | ||
complete_new_key_operation(attributes.lifetime, id, handle, gen_res) | ||
} | ||
|
||
/// Destroy a key | ||
|
@@ -113,8 +109,7 @@ pub fn generate(attributes: Attributes, id: Option<u32>) -> Result<Id> { | |
pub unsafe fn destroy(key: Id) -> Result<()> { | ||
initialized()?; | ||
let handle = key.handle()?; | ||
Status::from(psa_crypto_sys::psa_destroy_key(handle)).to_result()?; | ||
key.close_handle(handle) | ||
Status::from(psa_crypto_sys::psa_destroy_key(handle)).to_result() | ||
} | ||
|
||
/// Import a key in binary format | ||
|
@@ -166,26 +161,23 @@ pub unsafe fn destroy(key: Id) -> Result<()> { | |
pub fn import(attributes: Attributes, id: Option<u32>, data: &[u8]) -> Result<Id> { | ||
initialized()?; | ||
|
||
let mut attributes = psa_crypto_sys::psa_key_attributes_t::try_from(attributes)?; | ||
let mut key_attributes = psa_crypto_sys::psa_key_attributes_t::try_from(attributes)?; | ||
let id = if let Some(id) = id { | ||
unsafe { psa_crypto_sys::psa_set_key_id(&mut attributes, id) }; | ||
unsafe { psa_crypto_sys::psa_set_key_id(&mut key_attributes, id) }; | ||
id | ||
} else { | ||
0 | ||
}; | ||
let mut handle = 0; | ||
|
||
Status::from(unsafe { | ||
psa_crypto_sys::psa_import_key(&attributes, data.as_ptr(), data.len(), &mut handle) | ||
let gen_res = Status::from(unsafe { | ||
psa_crypto_sys::psa_import_key(&key_attributes, data.as_ptr(), data.len(), &mut handle) | ||
}) | ||
.to_result()?; | ||
.to_result(); | ||
|
||
Attributes::reset(&mut attributes); | ||
Attributes::reset(&mut key_attributes); | ||
|
||
Ok(Id { | ||
id, | ||
handle: Some(handle), | ||
}) | ||
complete_new_key_operation(attributes.lifetime, id, handle, gen_res) | ||
} | ||
|
||
/// Export a public key or the public part of a key pair in binary format | ||
|
@@ -227,17 +219,87 @@ pub fn export_public(key: Id, data: &mut [u8]) -> Result<usize> { | |
let handle = key.handle()?; | ||
let mut data_length = 0; | ||
|
||
Status::from(unsafe { | ||
let export_res = Status::from(unsafe { | ||
psa_crypto_sys::psa_export_public_key( | ||
handle, | ||
data.as_mut_ptr(), | ||
data.len(), | ||
&mut data_length, | ||
) | ||
}) | ||
.to_result()?; | ||
.to_result(); | ||
key.close_handle(handle)?; | ||
export_res?; | ||
Ok(data_length) | ||
} | ||
|
||
/// Gets the attributes for a given key ID | ||
/// | ||
/// The `Id` structure can be created with the `from_persistent_key_id` constructor on `Id`. | ||
/// | ||
/// # Example | ||
/// | ||
/// ``` | ||
/// # use psa_crypto::operations::key_management; | ||
/// # use psa_crypto::types::key::{Attributes, Type, Lifetime, Policy, UsageFlags}; | ||
/// # use psa_crypto::types::algorithm::{AsymmetricSignature, Hash}; | ||
/// # let mut attributes = Attributes { | ||
/// # key_type: Type::RsaKeyPair, | ||
/// # bits: 1024, | ||
/// # lifetime: Lifetime::Volatile, | ||
/// # policy: Policy { | ||
/// # usage_flags: UsageFlags { | ||
/// # sign_hash: true, | ||
/// # sign_message: true, | ||
/// # verify_hash: true, | ||
/// # verify_message: true, | ||
/// # ..Default::default() | ||
/// # }, | ||
/// # permitted_algorithms: AsymmetricSignature::RsaPkcs1v15Sign { | ||
/// # hash_alg: Hash::Sha256.into(), | ||
/// # }.into(), | ||
/// # }, | ||
/// # }; | ||
/// psa_crypto::init().unwrap(); | ||
/// let my_key = key_management::generate(attributes, None).unwrap(); | ||
/// //... | ||
/// 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 commentThe reason will be displayed to describe this comment to others. Learn more. In a way, this function is a contructor of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
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 commentThe 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 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hence my pet peeve with these cleanup methods. 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 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (Also, I think you don't need to call |
||
let handle = key.handle()?; | ||
let attributes_res = Status::from(unsafe { | ||
psa_crypto_sys::psa_get_key_attributes(handle, &mut key_attributes) | ||
}) | ||
.to_result(); | ||
key.close_handle(handle)?; | ||
attributes_res?; | ||
Ok(Attributes::try_from(key_attributes)?) | ||
} | ||
|
||
Ok(data_length) | ||
/// Completes a new key operation (either generate or import) | ||
/// | ||
/// If key is not `Volatile` (`Persistent` or `Custom(u32)`), handle is closed. | ||
/// | ||
/// If a key is `Volatile`, `Id` returned contains the key `handle`. Otherwise, it does not. | ||
fn complete_new_key_operation( | ||
key_lifetime: Lifetime, | ||
id: psa_key_id_t, | ||
handle: psa_key_handle_t, | ||
operation_result: Result<()>, | ||
) -> Result<Id> { | ||
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 commentThe reason will be displayed to describe this comment to others. Learn more. Do you think that if
So I think this is fine not passing There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have checked |
||
Ok(Id { | ||
id, | ||
handle: if key_lifetime == Lifetime::Volatile { | ||
Some(handle) | ||
} else { | ||
None | ||
}, | ||
}) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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 commentThe reason will be displayed to describe this comment to others. Learn more. Is the renaming of There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 😃 |
||
}; | ||
use serde::{Deserialize, Serialize}; | ||
|
||
/// Native definition of the attributes needed to fully describe | ||
|
@@ -473,7 +476,7 @@ pub struct UsageFlags { | |
#[cfg(feature = "with-mbed-crypto")] | ||
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)] | ||
pub struct Id { | ||
pub(crate) id: psa_crypto_sys::psa_key_id_t, | ||
pub(crate) id: key_id_type, | ||
pub(crate) handle: Option<psa_crypto_sys::psa_key_handle_t>, | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -186,6 +186,9 @@ impl From<psa_crypto_sys::psa_status_t> for Status { | |
psa_crypto_sys::PSA_ERROR_INVALID_PADDING => Error::InvalidPadding.into(), | ||
psa_crypto_sys::PSA_ERROR_INSUFFICIENT_DATA => Error::InsufficientData.into(), | ||
psa_crypto_sys::PSA_ERROR_INVALID_HANDLE => Error::InvalidHandle.into(), | ||
psa_crypto_sys::PSA_ERROR_CORRUPTION_DETECTED => Error::CorruptionDetected.into(), | ||
psa_crypto_sys::PSA_ERROR_DATA_CORRUPT => Error::DataCorrupt.into(), | ||
psa_crypto_sys::PSA_ERROR_DATA_INVALID => Error::DataInvalid.into(), | ||
s => { | ||
error!("{} not recognised as a valid PSA status.", s); | ||
Status::Error(Error::GenericError) | ||
|
@@ -218,19 +221,20 @@ impl From<Error> for psa_crypto_sys::psa_status_t { | |
Error::InsufficientStorage => psa_crypto_sys::PSA_ERROR_INSUFFICIENT_STORAGE, | ||
Error::CommunicationFailure => psa_crypto_sys::PSA_ERROR_COMMUNICATION_FAILURE, | ||
Error::StorageFailure => psa_crypto_sys::PSA_ERROR_STORAGE_FAILURE, | ||
//Error::DataCorrupt => psa_crypto_sys::PSA_ERROR_DATA_CORRUPT, | ||
//Error::DataInvalid => psa_crypto_sys::PSA_ERROR_DATA_INVALID, | ||
Error::DataCorrupt => psa_crypto_sys::PSA_ERROR_DATA_CORRUPT, | ||
Error::DataInvalid => psa_crypto_sys::PSA_ERROR_DATA_INVALID, | ||
Error::HardwareFailure => psa_crypto_sys::PSA_ERROR_HARDWARE_FAILURE, | ||
//Error::CorruptionDetected => psa_crypto_sys::PSA_ERROR_CORRUPTION_DETECTED, | ||
Error::CorruptionDetected => psa_crypto_sys::PSA_ERROR_CORRUPTION_DETECTED, | ||
Error::InsufficientEntropy => psa_crypto_sys::PSA_ERROR_INSUFFICIENT_ENTROPY, | ||
Error::InvalidSignature => psa_crypto_sys::PSA_ERROR_INVALID_SIGNATURE, | ||
Error::InvalidPadding => psa_crypto_sys::PSA_ERROR_INVALID_PADDING, | ||
Error::InsufficientData => psa_crypto_sys::PSA_ERROR_INSUFFICIENT_DATA, | ||
Error::InvalidHandle => psa_crypto_sys::PSA_ERROR_INVALID_HANDLE, | ||
e => { | ||
// 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 commentThe 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 commentThe reason will be displayed to describe this comment to others. Learn more. Will remove |
||
} | ||
} | ||
} | ||
|
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