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

Added the CanDoCrypto operation as well as fixing some of the other test scripts. #522

Merged
merged 1 commit into from
Sep 28, 2021

Conversation

Kakemone
Copy link
Contributor

Added the internal CanDoCrypto as a new capability_discovery file in the pkcs11 provider and made corresponding changes to the relevent files. Also added the end to end tests for CanDoCrypto and fixed the other tests that were still using the old syntax for the usage flags.

Signed-off-by: Sam Davis sam.davis@arm.com

@ionut-arm ionut-arm changed the base branch from main to can-do-crypto September 13, 2021 11:10
@Kakemone Kakemone force-pushed the CanDoCrypto_patch branch 9 times, most recently from 210e768 to bbfafae Compare September 14, 2021 11:07
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.

The function is quite convoluted - could you break it down into multiple methods/functions, maybe one for each of Use, Generate..., and maybe have a separate function for anything that is common?

Comment on lines 37 to 41
if !(attributes.bits == 192
|| attributes.bits == 224
|| attributes.bits == 256
|| attributes.bits == 384
|| attributes.bits == 512)
Copy link
Member

Choose a reason for hiding this comment

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

You could probably put these values in an array of constant and perform the check with contains, makes it a bit easier to read

Comment on lines 28 to 35
if attributes.key_type
== (Type::EccKeyPair {
curve_family: EccFamily::SecpR1,
})
|| attributes.key_type
== (Type::EccPublicKey {
curve_family: EccFamily::SecpR1,
})
Copy link
Member

Choose a reason for hiding this comment

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

This would be more readable with matches

Comment on lines 84 to 53
if std::any::type_name::<Ulong>() == std::any::type_name::<u64>() {
if !((attributes.bits as u64) >= (*mechanism_info.min_key_size()).into()
&& (attributes.bits as u64) <= (*mechanism_info.max_key_size()).into())
{
return Err(PsaErrorNotSupported);
}
} else {
if !((*mechanism_info.min_key_size() as u64) <= (attributes.bits as u64)
&& (attributes.bits as u64) <= (*mechanism_info.max_key_size() as u64))
{
return Err(PsaErrorNotSupported);
}
}
Copy link
Member

Choose a reason for hiding this comment

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

Just realised that there's a TryFrom<usize> for Ulong implemented that could help here (code here) (?)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't think that this will be that much better as <= and >= cannot be applied to Ulongs

Copy link
Member

Choose a reason for hiding this comment

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

There is a From<Ulong> for CK_ULONG implemented, that could help performing the operations on CK_ULONG not caring if that type is u32 or u64?

Copy link
Member

@hug-dev hug-dev left a comment

Choose a reason for hiding this comment

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

Thank you for this! It looks as a good start 👌 Added some comments here and there.

@@ -98,7 +99,7 @@ impl TestClient {
/// Creates a key with specific attributes.
pub fn generate_key(&mut self, key_name: String, attributes: Attributes) -> Result<()> {
self.basic_client
.psa_generate_key(key_name.clone(), attributes)
.psa_generate_key(&key_name.clone(), attributes)
Copy link
Member

Choose a reason for hiding this comment

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

Ideally here we would also change the prototype of the methods taking key name as String to &str as it was done in the client 😬 However that would imply a ton of change in the tests to change everything so probably better not to do it now. It's worth though to open a new issue indicating that this is something to be done!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I changed this as it threw an error when I was compiling

@@ -0,0 +1,371 @@
// Copyright 2021 Contributors to the Parsec project.
Copy link
Member

Choose a reason for hiding this comment

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

We might want to make capability_discovery an "all-providers" test. It might be nice to test that specific attributes work on one virtual crypto backend (software TPM, softHSM, etc) but not on others. As for CI the backend we use are fixed and versioned we can check what is supported there and make sure we return the correct info in Parsec.

edit: it's fine to keep it like this for now. We might also want to add tests where we first call can_do_crypto and then try to perform the operation with the same attribute if it succeeds.

A good test of this operation is to try to call it in the beginning of some e2e tests with the same attributes to make sure the test will succeed.


let status = client.can_do_crypto(CheckType::Use, attributes);

assert_eq!(Ok(()), status)
Copy link
Member

Choose a reason for hiding this comment

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

Same question here the mix between key type (RSA) and alg (ECDSA) is weird 🤔

Comment on lines 84 to 53
if std::any::type_name::<Ulong>() == std::any::type_name::<u64>() {
if !((attributes.bits as u64) >= (*mechanism_info.min_key_size()).into()
&& (attributes.bits as u64) <= (*mechanism_info.max_key_size()).into())
{
return Err(PsaErrorNotSupported);
}
} else {
if !((*mechanism_info.min_key_size() as u64) <= (attributes.bits as u64)
&& (attributes.bits as u64) <= (*mechanism_info.max_key_size() as u64))
{
return Err(PsaErrorNotSupported);
}
}
Copy link
Member

Choose a reason for hiding this comment

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

There is a From<Ulong> for CK_ULONG implemented, that could help performing the operations on CK_ULONG not caring if that type is u32 or u64?

Comment on lines 84 to 68
} else if !(attributes.policy.usage_flags.decrypt()
|| attributes.policy.usage_flags.encrypt()
|| attributes.policy.usage_flags.sign_hash()
|| attributes.policy.usage_flags.sign_message()
|| attributes.policy.usage_flags.verify_hash()
|| attributes.policy.usage_flags.verify_message())
{
return Err(PsaErrorNotSupported);
}
Copy link
Member

Choose a reason for hiding this comment

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

Not sure if we need to care about the usage_flags here.

Comment on lines 45 to 57
let supported_mechanisms: Vec<MechanismType> = self
.backend
.get_mechanism_list(self.slot_number)
.map_err(to_response_status)?;
let mechanism = Mechanism::try_from(attributes.policy.permitted_algorithms)
.map_err(to_response_status)?;
let mechanism_info: MechanismInfo = self
.backend
.get_mechanism_info(self.slot_number, mechanism.mechanism_type())
.map_err(to_response_status)?;
if !(supported_mechanisms.contains(&mechanism.mechanism_type())) {
return Err(PsaErrorNotSupported);
}
Copy link
Member

Choose a reason for hiding this comment

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

That's pretty clean!
I am thinking, maybe we should put that (and the key size check below) inside the use_check function? And replace the content of the if with just a call to use_check?

In the match at the end of the function we can check for CheckType::Use that the algorithm is not None.

Type::RsaKeyPair | Type::RsaPublicKey => (),
_ => return Err(PsaErrorNotSupported),
}
if attributes.policy.permitted_algorithms != Algorithm::None {
Copy link
Member

Choose a reason for hiding this comment

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

In the case it isn't None, maybe it would be good to call: attributes.compatible_with_alg(attributes.policy.permitted_algorithms)?; to make sure the algorithm is compatible with the key type. That will return PsaErrorNotPermitted which can be added as a possible return value from this operation in the contract. See here

@Kakemone Kakemone force-pushed the CanDoCrypto_patch branch 2 times, most recently from b2aecbc to aac48c0 Compare September 22, 2021 08:16
{
return Err(PsaErrorNotSupported);
}
attributes.compatible_with_alg(attributes.policy.permitted_algorithms)?;
Copy link
Member

Choose a reason for hiding this comment

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

Can you please make a PR on the book operation saying that NotPermitted is returned in that case if the alg is not compatible?

}))
{
return Err(PsaErrorNotSupported);
}
Copy link
Member

Choose a reason for hiding this comment

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

If attributes.policy.permitted_algorithms is not None, I think we should call use_check from here too. Same for import. I think some tests with non-compatible key type/algorithm are still passing because of that.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Calling use_check causes an issue as it checks if at least on of the the relevant usage flags are set which isn't applicable to import and generate so would it work to just run attributes.compatible_with_alg(attributes.policy.permitted_algorithms)?; to check if the type and algorithm match?

Copy link
Member

Choose a reason for hiding this comment

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

Reading the contract we have written now, I think it should be applicable?

For the Generate, Import and Derive check there is:

If the key_algorithm is not None, also perform the Use check.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

So are we saying that Generate and Import should have also have at least one of the relevant usage flags set? (And Derive but that is never supported by pkcs11)

Copy link
Member

Choose a reason for hiding this comment

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

I think so, if an Algorithm is set, it means that it should be used for at least something

…est scripts

Added the internal CanDoCrypto as a new capability_discovery file in the pkcs11 provider and made corresponding changes to the relevent files. Also added the end to end tests for CanDoCrypto and fixed the other tests that were still using the old syntax for the usage flags.

Signed-off-by: Sam Davis <sam.davis@arm.com>
Copy link
Member

@hug-dev hug-dev left a comment

Choose a reason for hiding this comment

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

Thanks for the change. I think since this is a development branch, work can continue on it to make things better little by little in further PRs.

It's really hard to cover everything now, I think we will improve it when adding it as a pre-requisite for our other e2e tests.

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.

Let's merge this as is and we'll make note of ways to improve the code in the original issue!

@hug-dev hug-dev merged commit b751323 into parallaxsecond:can-do-crypto Sep 28, 2021
@Kakemone Kakemone deleted the CanDoCrypto_patch branch August 31, 2022 10:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants