-
Notifications
You must be signed in to change notification settings - Fork 68
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 asymmetric encrypt and decrypt to Mbed Crypto provider #196
Conversation
This PR won't pass CI until |
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.
Looking good!
@@ -12,3 +12,4 @@ This file aims to acknowledge the specific contributors referred to in the "Cont | |||
* Ionut Mihalcea (@ionut-arm) | |||
* Hugues de Valon (@hug-dev) | |||
* Jesper Brynolf (@Superhepper) | |||
* Samuel Bailey (@sbailey-arm) |
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.
👌
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.
🌞
Cargo.toml
Outdated
zeroize = { version = "1.1.0", features = ["zeroize_derive"] } | ||
secrecy = { version = "0.6.0", features = ["serde"] } |
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 this needed? I didn't see any direct uses of it
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.
Nope, I have removed it. Wonder if there's a clippy
setting to catch that...
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.
WIP it seems
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 PR only provides the functionality of cargo-udeps in upstream tools. You can install it today!
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 @est31! We should definitely add that on our CIs!
let salt_buff = match &op.salt { | ||
Some(salt) => Some(salt.as_slice()), | ||
None => None, | ||
}; |
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 this what you're trying to achieve 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 don't think that's quite it. op.salt
is an Option<Zeroizing<Vec<u8>>>
and I need salt_buff
to be Option<&[u8]>
. There may still be some more concise way of writing it that I'm not aware of though.
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.
Huh! I thought that since Zeroizing
implements Deref
, it would work - actually, it seems as_deref
is what I should've recommended, though it doesn't solve the whole problem either - op.salt.as_deref()
yields Option<&Vec<u8>>
} | ||
Err(error) => { | ||
let error = ResponseStatus::from(error); | ||
format_error!("Encrypt status: {}", 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.
The format_error
macro doesn't need the {}
part of the "format string", that gets added inside the macro!
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.
Ah, that's why the log outputs have been a bit odd...!
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.
What about in this case?
format_error!(
"Error {} when opening a persistent Mbed Crypto key.",
e
);
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.
Ooops! I didn't notice that one when it went in... I wrote format_error
to always log in the same format "Brief description of problem; error: {}" - the last bit is only written when the config flag for verbose logging is on. You can probably change that to ("Failed to open persistent Mbed Crypto key", e)
} | ||
Err(error) => { | ||
// When dropped, will zero buffer incase anything was written before error | ||
let _ = Secret::new(plaintext); |
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.
Easier/quicker to just plaintext.zeroize()
here (though you need to import the Zeroize
trait).
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.
huh, I didn't know you could do that 🤯! How does it work? plaintext
is a regular Vec<u8>' and I can't see anything obvious in the documentation that states
Zeroizableis implemented for
Vec. Is it
u8implements
DefaultIsZeros, so implements
Zeroizablein the blanket implementation and
Vec` 'inherits' (derefs?) that?
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.
Zeroize
is implemented on Vec
s - it's actually what you were using in the other PR when doing plaintext.zeroize()
for the protobuf types - those types don't use Zeroizing
or anything from the crate
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.
Oh yeah... 🤦♂️
fn asym_encrypt_verify_decrypt_with_rsa_crate() { | ||
let key_name = String::from("asym_encrypt_verify_decrypt_with_rsa_crate"); | ||
let mut client = TestClient::new(); | ||
|
||
client.generate_rsa_encryption_keys_rsapkcs1v15crypt(key_name.clone()).unwrap(); | ||
let pub_key = client.export_public_key(key_name.clone()).unwrap(); | ||
|
||
let rsa_pub_key = RSAPublicKey::from_pkcs1(&pub_key).unwrap(); | ||
let ciphertext = rsa_pub_key.encrypt(&mut OsRng, PaddingScheme::new_pkcs1v15_encrypt(), &PLAINTEXT_MESSAGE).unwrap(); | ||
|
||
let plaintext = client.asymmetric_decrypt_message_with_rsapkcs1v15( | ||
key_name.clone(), | ||
ciphertext, | ||
).unwrap(); | ||
|
||
assert_eq!(&PLAINTEXT_MESSAGE[..], &plaintext[..]); | ||
|
||
} |
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.
🙆♂️ niiiiiice!
95fc26b
to
79a3a14
Compare
a678fcf
to
163bbd6
Compare
if client.provider() != Some(ProviderID::MbedCrypto) { | ||
// Not supported by current provider | ||
return; | ||
} |
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 there a neater way of doing this?
Would be nice if the tests could check which operations the current provider supports and only test those.
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.
You can always put an #[cfg(feature = "mbed-crypto-provider")]
on the 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.
Ah, this is in the e2e crate... Hmmm
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 the if
is 100% correct anyway, because you could have multiple providers set up and the client chooses a different one, doesn't mean the Mbed Crypto one isn't available. Maybe we should change the set_provider
method (on the test client) to check if the provider actually exists, and returns an error if not. Then we can check on that.
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.
client chooses a different one
Are the tests not done in isolation? As in, there will only ever be one provider at once during testing?
Maybe we should change the set_provider method (on the test client) to check if the provider actually exists, and returns an error if not. Then we can check on that.
So have set_provider
check basic_client.list_providers
to see if that provider exists (in this case, MbedCrypto
) and if it does, it returns Ok
and we can run the tests?
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.
Are the tests not done in isolation? As in, there will only ever be one provider at once during testing?
Yeah, that's true, this is in the per_provider test thing - forget that.
I think we can do it in another way, actually, makes it more scalable - call list_opcodes
and check if the operation you want is supported. If it isn't, return
. It's not ideal because it will still appear as a test even when it's not supported, but there's no need to do anything to enable the test when you implement it in some new provider.
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 we can do it in another way, actually, makes it more scalable - call list_opcodes and check if the operation you want is supported. If it isn't, return. It's not ideal because it will still appear as a test even when it's not supported, but there's no need to do anything to enable the test when you implement it in some new provider.
That sounds more like what I was thinking. The other two solutions don't deal with the fact that the tests are still run either. Could do with a way of forcing text output even if --show-output
isn't specified, so we can at least say 'Hey, this provider doesn't actually support this operation'. I can have a poke tomorrow.
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, it might be worth to change this check to:
if client.list_opcodes(client.provider().unwrap())?.contains(Opcode::PsaAsymmetricEncrypt) {
return;
}
We could even create a method out of that snippet in the client:
fn is_operation_supported(&self, op: Opcode) -> bool {
}
1f9f841
to
4b2fa81
Compare
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 a lot! That looks very good. A few comments but otherwise it's ok.
@@ -12,3 +12,4 @@ This file aims to acknowledge the specific contributors referred to in the "Cont | |||
* Ionut Mihalcea (@ionut-arm) | |||
* Hugues de Valon (@hug-dev) | |||
* Jesper Brynolf (@Superhepper) | |||
* Samuel Bailey (@sbailey-arm) |
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.
🌞
if client.provider() != Some(ProviderID::MbedCrypto) { | ||
// Not supported by current provider | ||
return; | ||
} |
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, it might be worth to change this check to:
if client.list_opcodes(client.provider().unwrap())?.contains(Opcode::PsaAsymmetricEncrypt) {
return;
}
We could even create a method out of that snippet in the client:
fn is_operation_supported(&self, op: Opcode) -> bool {
}
app_name: ApplicationName, | ||
op: psa_asymmetric_encrypt::Operation, | ||
) -> Result<psa_asymmetric_encrypt::Result> { | ||
info!("Mbed Provider - Asym Encrypt"); |
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 those info!
are not needed now that we have the ingress
/egress
trace everywhere
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.
Should they be removed from the other operations too?
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.
If you don't mind 👀
}) | ||
} | ||
Err(error) => { | ||
plaintext.zeroize(); |
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.
Ah good point! Do you think, even in case of error, it might contain some decrypted data? Does the spec say anything about it?
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.
hmm it doesn't mention it in the spec that I can see. A quick look at the mbedtls
code shows that it only copies into plaintext buffer if successful.
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 reckon that is the safe, default, behaviour that you would expect. We can remove the zeroize
here I think.
44f6795
to
e45d0e0
Compare
Signed-off-by: Samuel Bailey <samuel.bailey@arm.com>
e45d0e0
to
599d8d1
Compare
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 adressing the comments!
@@ -25,8 +25,6 @@ impl Pkcs11Provider { | |||
app_name: ApplicationName, | |||
op: psa_sign_hash::Operation, | |||
) -> Result<psa_sign_hash::Result> { | |||
info!("Pkcs11 Provider - Asym Sign"); |
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 removing those as well.
Signed-off-by: Samuel Bailey samuel.bailey@arm.com