Skip to content
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

Add consistency in key creation/deletion #324

Merged
merged 3 commits into from
Jan 27, 2021

Conversation

hug-dev
Copy link
Member

@hug-dev hug-dev commented Jan 21, 2021

on all providers.
Also make the core operations looping on all providers "best-effort" by
being infallible.

This is mainly for initial review/CI testing. This makes the assumption that this comment is agreed but I can change later on.

Fix #323
Fix #319
Fix #149

on all providers.
Also make the core operations looping on all providers "best-effort" by
being infallible.

Signed-off-by: Hugues de Valon <hugues.devalon@arm.com>
@hug-dev hug-dev requested a review from ionut-arm January 22, 2021 10:36
@hug-dev hug-dev added the multitenancy Getting Parsec to provide isolated key stores for multiple clients based on an identity mechanism label Jan 22, 2021
Copy link
Member

@ionut-arm ionut-arm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cheers for the changes, it's nice to make the providers more consistent

///
/// Returns PsaErrorAlreadyExists if the key triple already exists or KeyInfoManagerError for
/// another error.
pub fn already_exists(&self, key_triple: &KeyTriple) -> Result<(), ResponseStatus> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I get that the doc above says how this method works, but to me already_exists implies that Ok(()) would mean yes, not no - at least that's what I'd assume it does if I see it used somewhere in a PR. Maybe something like is_unique (or check_unique) matches the return type better? Or return Result<bool, ResponseStatus>?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah yes you are correct, now that I look at it it's kind of wrong 🤡
I changed the return type following the same kind of convention we use in the interface:

  • a method starting by is (an interrogation) return just a bool
  • a method which name is a declaration returns a Result

I can change the name to does_not_already_exist

@@ -99,7 +104,12 @@ impl Provide for Provider {

let mut clients: Vec<String> = Vec::new();
for provider in &self.prov_list {
let mut result = provider.list_clients(_op)?;
let mut result = provider.list_clients(_op).unwrap_or_else(|e| {
error!("list_clients failed on provider with {}", e);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any way to include the provider ID in that error message?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(same for the other methods that you changed)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I could do it with the describe method? I tried that rapidly but felt like it was going too far for this purpose

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, was wondering about that... I'm just thinking that since the operation is unlikely to proper fail and since logs are the only thing that tells you what fails maybe having more specific messages would help

Comment on lines 118 to 119
// If this fails, then we will have a zombie key in the Mbed Crypto backend. This
// is probably not a big problem apart from memory consumption.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It can still cause some operations to fail: if you restart the service and don't have a higher ID used (the IDs are allocated incrementally, right?) then you'll end up trying to use this one and that will fail, but the next generate/import will be fine, so it just needs a retry.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah yes you are correct, I guess this is the problem with this method... And will be the same with PKCS11 even though we use a random key ID generator: if it happens that we create the same key ID of a zombie key then the operation will have to be retried. In the worst case, if that happens a lot, one would have to re-try the key generation several times before finding an unallocated key ID.
Should we try to delete the key then, if insert_key_id fails? Here and for the PKCS11 provider.

@ionut-arm
Copy link
Member

Oh, there's one more issue that I forgot to put in the issue or note here:

In psa_destroy_key_internal in PKCS11 you have two destroy operations happening one after the other (because you could have two parts of a key), but currently if the first bit fails you just return - destroying the second part never happens. Now that you destroy the metadata regardless of that error code I think you should attempt to delete the 2nd part as well, regardless of what happens with the first one. I guess if either fails you return an error

@hug-dev
Copy link
Member Author

hug-dev commented Jan 25, 2021

I think you should attempt to delete the 2nd part as well

Yes, makes sense!

* Modifies the name of already_exists to does_not_exist
* Delete zombie keys in a best effort way 🧟
* in PKCS11, destroy key, try to destroy both parts of the key pair in a
  best effort way

Signed-off-by: Hugues de Valon <hugues.devalon@arm.com>
@hug-dev
Copy link
Member Author

hug-dev commented Jan 25, 2021

Addressed your comments in a new commit for easier review 🧟

Copy link
Member

@ionut-arm ionut-arm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, looks good, one question but it's just a nit

Comment on lines 466 to 472
if let Err(e) = first_res {
Err(e)
} else if let Err(e) = second_res {
Err(e)
} else {
Ok(psa_destroy_key::Result {})
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if let Err(e) = first_res {
Err(e)
} else if let Err(e) = second_res {
Err(e)
} else {
Ok(psa_destroy_key::Result {})
}
first_res?;
second_res?;
Ok(psa_destroy_key::Result {})

Would this work?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh yes that's nice 👌

@hug-dev
Copy link
Member Author

hug-dev commented Jan 26, 2021

I will also add the algorithm we follow for those things, in high level terms in the Provide trait for generate, import and delete so that future implementors can follow the same recipe.

To make future implementations consistent as well.
Also improves code snippet using ?.

Signed-off-by: Hugues de Valon <hugues.devalon@arm.com>
@hug-dev hug-dev merged commit 4ea43cc into parallaxsecond:master Jan 27, 2021
@hug-dev hug-dev deleted the delete-client-re branch January 27, 2021 14:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
multitenancy Getting Parsec to provide isolated key stores for multiple clients based on an identity mechanism
Projects
None yet
2 participants