-
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
First draft of rust-psa-crypto, Rust wrapper for (some of) mbed-crypto. #5
Conversation
You can execute the CI tests with |
Can I just do "git commit", "git push" to update this PR? |
Yes absolutely! git commit --amend
git push -f your_fork_remote_name first if you want to keep the history clean but we do not mind at all |
Seems like it failed on some |
Currently this depends on an old version of mbed-crypto. These files are adapted from Parsec: build-conf.toml, build.rs, setup_mbed_crypto.sh Signed-off-by: Edmund Grimley Evans <[email protected]>
I can't reproduce the remaining failure: Does it require a different version of Rust? |
I tried locally with the same version of Rust Travis CI uses (1.43.0) and I do not get any error... pub const shim_PSA_SUCCESS: psa_status_t = 0; in pub static shim_PSA_SUCCESS: psa_status_t = 0; on Aarch64? |
See this issue. In the prelude of the job it says:
That might be the problem. |
Ok try this to switch to a more recent Ubuntu version. diff --git a/.travis.yml b/.travis.yml
index 4f5fdb6..85d84e3 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,5 +1,6 @@
# Executing our tests on Arm64 with Travis CI
arch: arm64
+dist: bionic
language: rust
script:
- ./tests/ci.sh |
Signed-off-by: Edmund Grimley Evans <[email protected]>
That seemed to fix 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.
Thanks for the first PR!!
I made some comments. Some I think should be addressed in this PR but the ones marked "ignore" are general comments and can be ignored in this PR. I am happy to have this PR merged without the ignore comments but I think they need to be discussed and probably implemented in other PRs.
pub const PSA_KEY_TYPE_ECC_PUBLIC_KEY_BASE: psa_key_type_t = shim_PSA_KEY_TYPE_ECC_PUBLIC_KEY_BASE; | ||
pub const PSA_KEY_TYPE_ECC_KEY_PAIR_BASE: psa_key_type_t = shim_PSA_KEY_TYPE_ECC_KEY_PAIR_BASE; | ||
pub const PSA_KEY_TYPE_ECC_CURVE_MASK: psa_key_type_t = shim_PSA_KEY_TYPE_ECC_CURVE_MASK; | ||
pub const PSA_ECC_CURVE_SECT163K1: psa_ecc_curve_t = shim_PSA_ECC_CURVE_SECT163K1; | ||
pub const PSA_ECC_CURVE_SECT163R1: psa_ecc_curve_t = shim_PSA_ECC_CURVE_SECT163R1; | ||
pub const PSA_ECC_CURVE_SECT163R2: psa_ecc_curve_t = shim_PSA_ECC_CURVE_SECT163R2; | ||
pub const PSA_ECC_CURVE_SECT193R1: psa_ecc_curve_t = shim_PSA_ECC_CURVE_SECT193R1; | ||
pub const PSA_ECC_CURVE_SECT193R2: psa_ecc_curve_t = shim_PSA_ECC_CURVE_SECT193R2; | ||
pub const PSA_ECC_CURVE_SECT233K1: psa_ecc_curve_t = shim_PSA_ECC_CURVE_SECT233K1; | ||
pub const PSA_ECC_CURVE_SECT233R1: psa_ecc_curve_t = shim_PSA_ECC_CURVE_SECT233R1; | ||
pub const PSA_ECC_CURVE_SECT239K1: psa_ecc_curve_t = shim_PSA_ECC_CURVE_SECT239K1; | ||
pub const PSA_ECC_CURVE_SECT283K1: psa_ecc_curve_t = shim_PSA_ECC_CURVE_SECT283K1; | ||
pub const PSA_ECC_CURVE_SECT283R1: psa_ecc_curve_t = shim_PSA_ECC_CURVE_SECT283R1; | ||
pub const PSA_ECC_CURVE_SECT409K1: psa_ecc_curve_t = shim_PSA_ECC_CURVE_SECT409K1; | ||
pub const PSA_ECC_CURVE_SECT409R1: psa_ecc_curve_t = shim_PSA_ECC_CURVE_SECT409R1; | ||
pub const PSA_ECC_CURVE_SECT571K1: psa_ecc_curve_t = shim_PSA_ECC_CURVE_SECT571K1; | ||
pub const PSA_ECC_CURVE_SECT571R1: psa_ecc_curve_t = shim_PSA_ECC_CURVE_SECT571R1; | ||
pub const PSA_ECC_CURVE_SECP160K1: psa_ecc_curve_t = shim_PSA_ECC_CURVE_SECP160K1; | ||
pub const PSA_ECC_CURVE_SECP160R1: psa_ecc_curve_t = shim_PSA_ECC_CURVE_SECP160R1; | ||
pub const PSA_ECC_CURVE_SECP160R2: psa_ecc_curve_t = shim_PSA_ECC_CURVE_SECP160R2; | ||
pub const PSA_ECC_CURVE_SECP192K1: psa_ecc_curve_t = shim_PSA_ECC_CURVE_SECP192K1; | ||
pub const PSA_ECC_CURVE_SECP192R1: psa_ecc_curve_t = shim_PSA_ECC_CURVE_SECP192R1; | ||
pub const PSA_ECC_CURVE_SECP224K1: psa_ecc_curve_t = shim_PSA_ECC_CURVE_SECP224K1; | ||
pub const PSA_ECC_CURVE_SECP224R1: psa_ecc_curve_t = shim_PSA_ECC_CURVE_SECP224R1; | ||
pub const PSA_ECC_CURVE_SECP256K1: psa_ecc_curve_t = shim_PSA_ECC_CURVE_SECP256K1; | ||
pub const PSA_ECC_CURVE_SECP256R1: psa_ecc_curve_t = shim_PSA_ECC_CURVE_SECP256R1; | ||
pub const PSA_ECC_CURVE_SECP384R1: psa_ecc_curve_t = shim_PSA_ECC_CURVE_SECP384R1; | ||
pub const PSA_ECC_CURVE_SECP521R1: psa_ecc_curve_t = shim_PSA_ECC_CURVE_SECP521R1; | ||
pub const PSA_ECC_CURVE_BRAINPOOL_P256R1: psa_ecc_curve_t = shim_PSA_ECC_CURVE_BRAINPOOL_P256R1; | ||
pub const PSA_ECC_CURVE_BRAINPOOL_P384R1: psa_ecc_curve_t = shim_PSA_ECC_CURVE_BRAINPOOL_P384R1; | ||
pub const PSA_ECC_CURVE_BRAINPOOL_P512R1: psa_ecc_curve_t = shim_PSA_ECC_CURVE_BRAINPOOL_P512R1; | ||
pub const PSA_ECC_CURVE_CURVE25519: psa_ecc_curve_t = shim_PSA_ECC_CURVE_CURVE25519; | ||
pub const PSA_ECC_CURVE_CURVE448: psa_ecc_curve_t = shim_PSA_ECC_CURVE_CURVE448; | ||
pub const PSA_ALG_VENDOR_FLAG: psa_algorithm_t = shim_PSA_ALG_VENDOR_FLAG; | ||
pub const PSA_ALG_CATEGORY_MASK: psa_algorithm_t = shim_PSA_ALG_CATEGORY_MASK; | ||
pub const PSA_ALG_CATEGORY_HASH: psa_algorithm_t = shim_PSA_ALG_CATEGORY_HASH; | ||
pub const PSA_ALG_CATEGORY_MAC: psa_algorithm_t = shim_PSA_ALG_CATEGORY_MAC; | ||
pub const PSA_ALG_CATEGORY_CIPHER: psa_algorithm_t = shim_PSA_ALG_CATEGORY_CIPHER; | ||
pub const PSA_ALG_CATEGORY_AEAD: psa_algorithm_t = shim_PSA_ALG_CATEGORY_AEAD; | ||
pub const PSA_ALG_CATEGORY_SIGN: psa_algorithm_t = shim_PSA_ALG_CATEGORY_SIGN; | ||
pub const PSA_ALG_CATEGORY_ASYMMETRIC_ENCRYPTION: psa_algorithm_t = | ||
shim_PSA_ALG_CATEGORY_ASYMMETRIC_ENCRYPTION; | ||
pub const PSA_ALG_CATEGORY_KEY_AGREEMENT: psa_algorithm_t = shim_PSA_ALG_CATEGORY_KEY_AGREEMENT; | ||
pub const PSA_ALG_CATEGORY_KEY_DERIVATION: psa_algorithm_t = shim_PSA_ALG_CATEGORY_KEY_DERIVATION; | ||
pub const PSA_ALG_HASH_MASK: psa_algorithm_t = shim_PSA_ALG_HASH_MASK; | ||
pub const PSA_ALG_MD2: psa_algorithm_t = shim_PSA_ALG_MD2; | ||
pub const PSA_ALG_MD4: psa_algorithm_t = shim_PSA_ALG_MD4; | ||
pub const PSA_ALG_MD5: psa_algorithm_t = shim_PSA_ALG_MD5; | ||
pub const PSA_ALG_RIPEMD160: psa_algorithm_t = shim_PSA_ALG_RIPEMD160; | ||
pub const PSA_ALG_SHA_1: psa_algorithm_t = shim_PSA_ALG_SHA_1; | ||
pub const PSA_ALG_SHA_224: psa_algorithm_t = shim_PSA_ALG_SHA_224; | ||
pub const PSA_ALG_SHA_256: psa_algorithm_t = shim_PSA_ALG_SHA_256; | ||
pub const PSA_ALG_SHA_384: psa_algorithm_t = shim_PSA_ALG_SHA_384; | ||
pub const PSA_ALG_SHA_512: psa_algorithm_t = shim_PSA_ALG_SHA_512; | ||
pub const PSA_ALG_SHA_512_224: psa_algorithm_t = shim_PSA_ALG_SHA_512_224; | ||
pub const PSA_ALG_SHA_512_256: psa_algorithm_t = shim_PSA_ALG_SHA_512_256; | ||
pub const PSA_ALG_SHA3_224: psa_algorithm_t = shim_PSA_ALG_SHA3_224; | ||
pub const PSA_ALG_SHA3_256: psa_algorithm_t = shim_PSA_ALG_SHA3_256; | ||
pub const PSA_ALG_SHA3_384: psa_algorithm_t = shim_PSA_ALG_SHA3_384; | ||
pub const PSA_ALG_SHA3_512: psa_algorithm_t = shim_PSA_ALG_SHA3_512; | ||
pub const PSA_ALG_ANY_HASH: psa_algorithm_t = shim_PSA_ALG_ANY_HASH; | ||
pub const PSA_ALG_MAC_SUBCATEGORY_MASK: psa_algorithm_t = shim_PSA_ALG_MAC_SUBCATEGORY_MASK; | ||
pub const PSA_ALG_HMAC_BASE: psa_algorithm_t = shim_PSA_ALG_HMAC_BASE; | ||
pub const PSA_ALG_MAC_TRUNCATION_MASK: psa_algorithm_t = shim_PSA_ALG_MAC_TRUNCATION_MASK; | ||
pub const PSA_ALG_CIPHER_MAC_BASE: psa_algorithm_t = shim_PSA_ALG_CIPHER_MAC_BASE; | ||
pub const PSA_ALG_CBC_MAC: psa_algorithm_t = shim_PSA_ALG_CBC_MAC; | ||
pub const PSA_ALG_CMAC: psa_algorithm_t = shim_PSA_ALG_CMAC; | ||
pub const PSA_ALG_CIPHER_STREAM_FLAG: psa_algorithm_t = shim_PSA_ALG_CIPHER_STREAM_FLAG; | ||
pub const PSA_ALG_CIPHER_FROM_BLOCK_FLAG: psa_algorithm_t = shim_PSA_ALG_CIPHER_FROM_BLOCK_FLAG; | ||
pub const PSA_ALG_ARC4: psa_algorithm_t = shim_PSA_ALG_ARC4; | ||
pub const PSA_ALG_CTR: psa_algorithm_t = shim_PSA_ALG_CTR; | ||
pub const PSA_ALG_CFB: psa_algorithm_t = shim_PSA_ALG_CFB; | ||
pub const PSA_ALG_OFB: psa_algorithm_t = shim_PSA_ALG_OFB; | ||
pub const PSA_ALG_XTS: psa_algorithm_t = shim_PSA_ALG_XTS; | ||
pub const PSA_ALG_CBC_NO_PADDING: psa_algorithm_t = shim_PSA_ALG_CBC_NO_PADDING; | ||
pub const PSA_ALG_CBC_PKCS7: psa_algorithm_t = shim_PSA_ALG_CBC_PKCS7; | ||
pub const PSA_ALG_CCM: psa_algorithm_t = shim_PSA_ALG_CCM; | ||
pub const PSA_ALG_GCM: psa_algorithm_t = shim_PSA_ALG_GCM; | ||
pub const PSA_ALG_AEAD_TAG_LENGTH_MASK: psa_algorithm_t = shim_PSA_ALG_AEAD_TAG_LENGTH_MASK; | ||
pub const PSA_ALG_RSA_PKCS1V15_SIGN_BASE: psa_algorithm_t = shim_PSA_ALG_RSA_PKCS1V15_SIGN_BASE; | ||
pub const PSA_ALG_RSA_PSS_BASE: psa_algorithm_t = shim_PSA_ALG_RSA_PSS_BASE; | ||
pub const PSA_ALG_DSA_BASE: psa_algorithm_t = shim_PSA_ALG_DSA_BASE; | ||
pub const PSA_ALG_DETERMINISTIC_DSA_BASE: psa_algorithm_t = shim_PSA_ALG_DETERMINISTIC_DSA_BASE; | ||
pub const PSA_ALG_DSA_DETERMINISTIC_FLAG: psa_algorithm_t = shim_PSA_ALG_DSA_DETERMINISTIC_FLAG; | ||
pub const PSA_ALG_ECDSA_BASE: psa_algorithm_t = shim_PSA_ALG_ECDSA_BASE; | ||
pub const PSA_ALG_DETERMINISTIC_ECDSA_BASE: psa_algorithm_t = shim_PSA_ALG_DETERMINISTIC_ECDSA_BASE; | ||
pub const PSA_ALG_RSA_PKCS1V15_CRYPT: psa_algorithm_t = shim_PSA_ALG_RSA_PKCS1V15_CRYPT; | ||
pub const PSA_ALG_RSA_OAEP_BASE: psa_algorithm_t = shim_PSA_ALG_RSA_OAEP_BASE; | ||
pub const PSA_ALG_HKDF_BASE: psa_algorithm_t = shim_PSA_ALG_HKDF_BASE; | ||
pub const PSA_ALG_TLS12_PRF_BASE: psa_algorithm_t = shim_PSA_ALG_TLS12_PRF_BASE; | ||
pub const PSA_ALG_TLS12_PSK_TO_MS_BASE: psa_algorithm_t = shim_PSA_ALG_TLS12_PSK_TO_MS_BASE; | ||
pub const PSA_ALG_KEY_DERIVATION_MASK: psa_algorithm_t = shim_PSA_ALG_KEY_DERIVATION_MASK; | ||
pub const PSA_KEY_LIFETIME_VOLATILE: psa_key_lifetime_t = shim_PSA_KEY_LIFETIME_VOLATILE; | ||
pub const PSA_KEY_LIFETIME_PERSISTENT: psa_key_lifetime_t = shim_PSA_KEY_LIFETIME_PERSISTENT; | ||
pub const PSA_KEY_USAGE_EXPORT: psa_key_usage_t = shim_PSA_KEY_USAGE_EXPORT; | ||
pub const PSA_KEY_USAGE_ENCRYPT: psa_key_usage_t = shim_PSA_KEY_USAGE_ENCRYPT; | ||
pub const PSA_KEY_USAGE_DECRYPT: psa_key_usage_t = shim_PSA_KEY_USAGE_DECRYPT; | ||
pub const PSA_KEY_USAGE_SIGN: psa_key_usage_t = shim_PSA_KEY_USAGE_SIGN; | ||
pub const PSA_KEY_USAGE_VERIFY: psa_key_usage_t = shim_PSA_KEY_USAGE_VERIFY; | ||
pub const PSA_KEY_USAGE_DERIVE: psa_key_usage_t = shim_PSA_KEY_USAGE_DERIVE; |
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.
Maybe we can directly access the const
generated by bindgen
?
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 so and as we are not using PSA_KEY_SLOT_COUNT
and PSA_MAX_PERSISTENT_KEY_IDENTIFIER
, we could even delete this file.
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 can't immediately see how to do that. Processing the psa/crypto.h
header file with bindgen
gives you nothing for PSA_SUCCESS
and many other symbols (rust-lang/rust-bindgen#316). So you need to write some C code that uses the preprocessor symbols. That C code includes psa/crypto.h
, so processing it with bindgen
gives you a load of stuff that you don't want to make public (a limitation of the C preprocessor). So you need a list of the symbols that you do want to make public. Moreover, the symbol in your C code can't be the same as the psa/crypto.h
symbol (another limitation of the C preprocessor). So if you want the Rust library to export a symbol with the same name as in psa/crypto.h
you end up with something similar to what I've done.
Or is there a totally different approach? Or a bindgen
option that saves us? (There are various --whitelist-...
options, for example, which might solve one of the problems mentioned above.)
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 can't immediately see how to do that. Processing the psa/crypto.h header file with bindgen gives you nothing for PSA_SUCCESS and many other symbols (rust-lang/rust-bindgen#316). So you need to write some C code that uses the preprocessor symbols.
I agree with that.
So you need to write some C code that uses the preprocessor symbols. That C code includes psa/crypto.h, so processing it with bindgen gives you a load of stuff that you don't want to make public (a limitation of the C preprocessor).
Oh I see what you mean now: we only want to make public the useful symbols of bindgen
. Doing that also ensure us that those symbols are stable across crate versions.
I think my point came from similar ideas expressed in other comments, if we want this crate to be more idiomatic (in my idea of what is idiomatic), we would replace those value with our own constructs and use the bindgen
values there in conversion functions.
For example we might create a Hash
enumeration which contains all the hash algorithm values. Having a defined type for that help restrict some functions to only take a Hash
as a parameter. Similarly with other values found there.
We did a lot of this work in Parsec interface and I am sure we can reuse a lot of it.
// Copyright 2020 Contributors to the Parsec project. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
#include "shim.h" |
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.
A comment would be nice here to explain why do we need this file, maybe link to this issue as well.
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.
Done.
impl Global { | ||
fn new() -> Global { | ||
Global { | ||
init_succeeded: false, | ||
key_mutex: Mutex::new(()), | ||
} | ||
} | ||
} | ||
|
||
lazy_static! { | ||
static ref GLOBAL: Mutex<Global> = Mutex::new(Global::new()); | ||
} | ||
|
||
fn init() -> bool { | ||
if GLOBAL.lock().unwrap().init_succeeded { | ||
return true; | ||
} | ||
let status = unsafe { psa_crypto_binding::psa_crypto_init() }; | ||
if status != PSA_SUCCESS { | ||
return false; | ||
} | ||
GLOBAL.lock().unwrap().init_succeeded = true; | ||
true | ||
} | ||
|
||
macro_rules! wrap_any { | ||
($x:expr) => { | ||
if !init() { | ||
panic!("Error when initialising PSA Crypto") | ||
} else { | ||
#[allow(unused_unsafe)] | ||
unsafe { | ||
$x | ||
} | ||
} | ||
}; | ||
} | ||
|
||
macro_rules! wrap_status { | ||
($x:expr) => { | ||
if !init() { | ||
PSA_ERROR_BAD_STATE | ||
} else { | ||
unsafe { $x } | ||
} | ||
}; | ||
} | ||
|
||
macro_rules! key_lock { | ||
($x:expr) => {{ | ||
let mutex = &GLOBAL.lock().unwrap().key_mutex; | ||
let _guard = mutex.lock().unwrap(); | ||
$x | ||
}}; | ||
} |
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.
ignore
I am not a Rust expert but I think the class + methods paradigm would be more idiomatic (and efficient) in this case.
You could have:
struct PsaCrypto {
// Calls to psa_open_key, psa_generate_key and psa_destroy_key
// are not thread safe. We work around this bug with the key_mutex.
// Mbed issue: https://github.com/ARMmbed/mbed-crypto/issues/266
key_mutex: Mutex<()>,
}
A new
static method could initialise the library and returns a PsaCrypto
instance and the other PSA Crypto operations would be implemented as methods on this struct.
That way you don't need to check and to lock a mutex everytime you want to call an operation as this is checked statically.
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.
This is worth discussing, but what you've suggested could be misleading if there can only be one instance of this structure. What I've done is quite likely not idiomatic Rust, but perhaps a wrapper for a C library should not be expected to look like idiomatic Rust.
(Turning PSA Crypto's single global space of key IDs into a separate space for each application is Parsec's job, right?)
(The mutex is only there to work around a bug in some versions of Mbed Crypto. It would seem wrong to optimise the Rust wrapper's API for working around a bug that will eventually disappear. I don't know what the plans are for the initialisation requirement. If that were to be removed then there would be no need for the mutex or any static data in the Rust wrapper, I think.)
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.
This is worth discussing, but what you've suggested could be misleading if there can only be one instance of this structure.
Good point! We can explore options how to create singletons. Having one instance of PsaCrypto
would allow you to leverage the Rust borrow-checker to have thread-safety without a mutex.
perhaps a wrapper for a C library should not be expected to look like idiomatic Rust
I tend to disagree with that point. I think Rust developpers consuming this crate will expect it to follow the usual Rust patterns. In the end "idiomatic" just means easy to use in a Rust context: safe and convenient abstractions. I do not think we should force the C style on Rust.
(Turning PSA Crypto's single global space of key IDs into a separate space for each application is Parsec's job, right?)
That is correct! By "abstraction" I do not mean to achieve that. I do think that we should provide the exact same features/functionalities than PSA Crypto with the same semantics. Still use Key ID. By abstraction I mean using the high-level features of Rust: stricter types with methods being the most important one for a Rust to C wrapper in my opinion.
(The mutex is only there to work around a bug in some versions of Mbed Crypto. It would seem wrong to optimise the Rust wrapper's API for working around a bug that will eventually disappear. I don't know what the plans are for the initialisation requirement. If that were to be removed then there would be no need for the mutex or any static data in the Rust wrapper, I think.)
In this message I meant the mutex that is needed around the GLOBAL
structure.
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.
Seems this hasn't been mentioned yet: std::sync::Once
; Not necessarily saying we should use it here, it just looks useful/aligned with the task at hand
Also, while I'm not a fan of the "panic if used twice" pattern, this page has some good points about having the compiler do some of the sanity checks for you.
src/lib.rs
Outdated
pub fn psa_get_key_bits(attributes: &psa_key_attributes_t) -> usize { | ||
wrap_any!((*attributes).x.core.bits as usize) | ||
} | ||
|
||
pub fn psa_get_key_type(attributes: &psa_key_attributes_t) -> psa_key_type_t { | ||
wrap_any!((*attributes).x.core.type_) | ||
} |
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.
Could those two getters be defined in the shim as well?
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 should be. Done.
pub fn psa_import_key( | ||
attributes: *const psa_key_attributes_t, | ||
data: *const u8, | ||
data_length: usize, | ||
handle: *mut psa_key_handle_t, | ||
) -> psa_status_t { |
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.
ignore
I think we ought to aim to not have any unsafe/non-idiomatic types in our public API. In particular:
- a Rust abstraction for
psa_key_attributes_t
andpsa_algorithm_t
. The setters/getters on the key attributes could even be implemented as methods on the new type we create. See Create abstractions of key attributes and algorithms #2 - in our APIs, instead of having for buffer a raw pointer (
*const u8
) and a size, have aVec<u8>
and use methods on it to convert it to what the C API expects. See Create the Rust representation of PSA Crypto operations #3 - have all our operations return a
Result
, which contains the data that the operation returns (or()
if nothing) or an error (apsa_status_t
, abstracted) if there was an 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.
All worth discussing. Currently I have wrapped psa_key_attributes_t
, so its internals are hidden, I think, but I haven't wrapped psa_algorithm_t
, which is therefore visible to the user of the Rust wrapper as a u32
(with the current Mbed 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.
I think this is good, we can continue making changes on top of it!
#[allow(non_camel_case_types)] | ||
pub struct psa_key_attributes_t { | ||
x: psa_crypto_binding::psa_key_attributes_t, | ||
} |
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.
This is ok as is for now, but we'll have to decide if we want to keep the naming convention from the C spec or if we want to make this truly Rust-native and use the camel case naming convention.
Also, if you're not interested in having a proper name for the internal value, you can simply do
pub struct psa_key_attributes_t(psa_crypto_binding::psa_key_attributes_t);
and access it through self.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.
Converting names to the Rust naming convention seems like a good idea to me. Anyone else in favour or opposed?
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 it is a good idea too but maybe in a later PR where we "rustify" other things as well?
Signed-off-by: Edmund Grimley Evans <[email protected]>
I think this is good to be merged as it is. We can continue discussing the different points and add more PRs on top of that if we agree. |
Hi @egrimley-arm I think I am going to work on this crate as well, as part of parallaxsecond/parsec#128, as I need to convert key attributes between the FFI types and the Rust native types we use in Parsec. What I think the next steps could be:
|
I'd be happy to see this merged. Is there any point in keeping static linking as an alternative? Or too much work to maintain? Having two layers sounds sensible. There might be some choices to make about what belongs in which layer. For example, making the methods thread-safe is a bug workaround, as I understand it, which could arguably belong in the lower layer, closer to where the bug is. Is the intention to make the abstraction layer independent of the PSA Crypto API version? I haven't looked at the PSA (draft) APIs hard enough to know whether that's feasible. |
Merged it as a base to work on.
I think you are right and that should be the case. I actually started reading what was the common way of providing Rust wrappers around C libraries. This and this are very good read and I think we should align to what they describe. There are good example of this in the Mbed TLS crate and this one.
We will have to check if the bug is still there with the version 1.0 of the API. Also, I do not know if we should fix a bug that is inside one implementation of the API and not the specification. I would say that as long as we respect the conditions described by the API which make its use memory and thread safe, then we are fine.
I think it will still be targeted at a specific API version. The abstraction I have in mind is just a systematic translation of the specification into Rust idiomatic types so it should pretty straightforward to do. Maybe there could be layers on top of that which give even more abstractions and would be independant of PSA Crypto API version but I am not sure it would be the goal of this crate. |
Currently this depends on an old version of mbed-crypto.
These files are adapted from Parsec:
build-conf.toml, build.rs, setup_mbed_crypto.sh