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 export_key #40

Merged
merged 1 commit into from
Jul 13, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions psa-crypto-sys/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,9 @@ pub use types::*;
#[cfg(feature = "implementation-defined")]
pub use psa_crypto_binding::{
psa_asymmetric_decrypt, psa_asymmetric_encrypt, psa_close_key, psa_crypto_init,
psa_destroy_key, 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,
psa_destroy_key, psa_export_key, 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
Expand Down
1 change: 1 addition & 0 deletions psa-crypto/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ zeroize = { version = "1.1.0", features = ["zeroize_derive"] }
[dev-dependencies]
rsa = "0.3.0"
rand = "0.7.3"
base64 = "0.12.3"

[features]
default = ["with-mbed-crypto", "no-std"]
Expand Down
54 changes: 53 additions & 1 deletion psa-crypto/src/operations/key_management.rs
Original file line number Diff line number Diff line change
Expand Up @@ -228,8 +228,60 @@ pub fn export_public(key: Id, data: &mut [u8]) -> Result<usize> {
)
})
.to_result();
key.close_handle(handle)?;
let handle_close_res = key.close_handle(handle);
export_res?;
handle_close_res?;
Ok(data_length)
}

/// Export a key pair in binary format
///
/// The key is written in `data`. The functions returns the number of bytes written.
/// Please check the PSA Crypto API for a more complete description on the format of `data`.
///
/// # 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,
/// # export: true,
/// # ..Default::default()
/// # },
/// # permitted_algorithms: AsymmetricSignature::RsaPkcs1v15Sign {
/// # hash_alg: Hash::Sha256.into(),
/// # }.into(),
/// # },
/// # };
/// psa_crypto::init().unwrap();
/// let buffer_size = attributes.export_key_output_size().unwrap();
/// let mut data = vec![0; buffer_size];
/// let my_key = key_management::generate(attributes, None).unwrap();
/// let size = key_management::export_key(my_key, &mut data).unwrap();
/// data.resize(size, 0);
/// ```
pub fn export_key(key: Id, data: &mut [u8]) -> Result<usize> {
initialized()?;
let handle = key.handle()?;
let mut data_length = 0;

let export_res = Status::from(unsafe {
psa_crypto_sys::psa_export_key(handle, data.as_mut_ptr(), data.len(), &mut data_length)
})
.to_result();
let handle_close_res = key.close_handle(handle);
export_res?;
handle_close_res?;
Ok(data_length)
}

Expand Down
71 changes: 65 additions & 6 deletions psa-crypto/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,62 @@ fn import_integration_test() {
}
}

#[test]
fn export_key_pair_test() {
Copy link
Member

Choose a reason for hiding this comment

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

Would it be possible to have a test where you put a previously generated key file in the right place and export that key? It would help with more accurate testing (instead of just making sure you get something on the other side). Would also help with testing in Parsec, as we won't have to be that thorough when testing there.

Copy link
Member

Choose a reason for hiding this comment

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

I guess another option is to import and export a "static" key (i.e. a byte vector).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You mean like has been done in Parsec? Yes I can add that test here. I wasn't sure what kind of/how many tests are added to psa-crypto as there are only generate and import tests there currently.

Copy link
Member

Choose a reason for hiding this comment

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

Yes, I think it makes more sense to put the tests at the lowest level where they apply - then neither Parsec nor other users of the crate need to test for 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.

Ah ok, good point. I've used the PK from Parsec's test, imported it, exported it, and verified the original an exported values match.

const PRIVATE_KEY: &str = "MIICWwIBAAKBgQCd+EKeRmZCKLmg7LasWqpKA9/01linY75ujilf6v/Kb8UP9r/E\
cO75Pvi2YPnYhBadmVOVxMOqS2zmKm1a9VTegT8dN9Unf2s2KbKrKXupaQTXcrGG\
SB/BmHeWeiqidEMw7i9ysjHK4KEuacmYmZpvKAnNWMyvQgjGgGNpsNzqawIDAQAB\
AoGAcHlAxXyOdnCUqpWgAtuS/5v+q06qVJRaFFE3+ElT0oj+ID2pkG5wWBqT7xbh\
DV4O1CtFLg+o2OlXIhH3RpoC0D0x3qfvDpY5nJUUhP/w7mtGOwvB08xhXBN2M9fk\
PNqGdrzisvxTry3rp9qDduZlv1rTCsx8+ww3iI4Q0coD4fECQQD4KAMgIS7Vu+Vm\
zQmJfVfzYCVdr4X3Z/JOEexb3eu9p1Qj904sLu9Ds5NO7atT+qtDYVxgH5kQIrKk\
mFNAx3NdAkEAovZ+DaorhkDiL/gFVzwoShyc1A6AWkH791sDlns2ETZ1WwE/ccYu\
uJill/5XA9RKw6whUDzzNTsv7bFkCruAZwJARP5y6ALxz5DfFfbZuPU1d7/6g5Ki\
b4fh8VzAV0ZbHa6hESLYBCbEdRE/WolvwfiGl0RBd6QxXTAYdPS46ODLLQJARrz4\
urXDbuN7S5c9ukBCvOjuqp4g2Q0LcrPvOsMBFTeueXJxN9HvNfIM741X+DGOwqFV\
VJ8gc1rd0y/NXVtGwQJAc2w23nTmZ/olcMVRia1+AFsELcCnD+JqaJ2AEF1Ng6Ix\
V/X2l32v6t3B57sw/8ce3LCheEdqLHlSOpQiaD7Qfw==";

let attributes = Attributes {
key_type: Type::RsaKeyPair,
bits: 1024,
lifetime: Lifetime::Volatile,
policy: Policy {
usage_flags: UsageFlags {
sign_hash: true,
verify_hash: true,
sign_message: true,
verify_message: true,
export: true,
encrypt: false,
decrypt: false,
cache: false,
copy: false,
derive: false,
},
permitted_algorithms: AsymmetricSignature::RsaPkcs1v15Sign {
hash_alg: Hash::Sha256.into(),
}
.into(),
},
};
psa_crypto::init().unwrap();
let mut test_client = test_tools::TestClient::new();
let decoded_pk = base64::decode(PRIVATE_KEY).unwrap();

let id = test_client.import(attributes, 201, &decoded_pk);

let buffer_size = attributes.export_key_output_size().unwrap();
let mut data = vec![0; buffer_size];
let size = test_client.export_key_pair(id, &mut data).unwrap();
data.resize(size, 0);
assert_eq!(decoded_pk, data);
}

mod test_tools {
use psa_crypto::operations::key_management;
use psa_crypto::types::key::{Attributes, Id};
use psa_crypto::types::status::Result;

pub struct TestClient {
keys: Vec<Id>,
Expand All @@ -92,14 +145,20 @@ mod test_tools {
TestClient { keys: Vec::new() }
}

pub fn generate(&mut self, attributes: Attributes, key_id: u32) {
self.keys
.push(key_management::generate(attributes, Some(key_id)).unwrap());
pub fn generate(&mut self, attributes: Attributes, key_id: u32) -> Id {
let id = key_management::generate(attributes, Some(key_id)).unwrap();
self.keys.push(id);
id
}

pub fn import(&mut self, attributes: Attributes, key_id: u32, key_data: &[u8]) -> Id {
let id = key_management::import(attributes, Some(key_id), key_data).unwrap();
self.keys.push(id);
id
}

pub fn import(&mut self, attributes: Attributes, key_id: u32, key_data: &[u8]) {
self.keys
.push(key_management::import(attributes, Some(key_id), key_data).unwrap());
pub fn export_key_pair(&mut self, key_id: Id, key_data: &mut [u8]) -> Result<usize> {
key_management::export_key(key_id, key_data)
}
}

Expand Down