diff --git a/psa-crypto-sys/src/lib.rs b/psa-crypto-sys/src/lib.rs index 6144d7b..3c95ace 100644 --- a/psa-crypto-sys/src/lib.rs +++ b/psa-crypto-sys/src/lib.rs @@ -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 diff --git a/psa-crypto/Cargo.toml b/psa-crypto/Cargo.toml index 6fc14f3..318e3c9 100644 --- a/psa-crypto/Cargo.toml +++ b/psa-crypto/Cargo.toml @@ -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"] diff --git a/psa-crypto/src/operations/key_management.rs b/psa-crypto/src/operations/key_management.rs index f1c2df0..43b078d 100644 --- a/psa-crypto/src/operations/key_management.rs +++ b/psa-crypto/src/operations/key_management.rs @@ -228,8 +228,60 @@ pub fn export_public(key: Id, data: &mut [u8]) -> Result { ) }) .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 { + 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) } diff --git a/psa-crypto/tests/mod.rs b/psa-crypto/tests/mod.rs index 9959989..478a6e6 100644 --- a/psa-crypto/tests/mod.rs +++ b/psa-crypto/tests/mod.rs @@ -78,9 +78,62 @@ fn import_integration_test() { } } +#[test] +fn export_key_pair_test() { + 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, @@ -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 { + key_management::export_key(key_id, key_data) } }