From 599d8d1f1c898b1e3d34e339afaab6f20d82221c Mon Sep 17 00:00:00 2001 From: Samuel Bailey Date: Wed, 1 Jul 2020 18:05:35 +0100 Subject: [PATCH] Added asymmetric encrypt and decrypt to Mbed Crypto provider Signed-off-by: Samuel Bailey --- CONTRIBUTORS.md | 1 + Cargo.lock | 21 +- Cargo.toml | 4 +- e2e_tests/Cargo.toml | 4 +- e2e_tests/src/lib.rs | 147 ++++++++++++- .../normal_tests/asym_encryption.rs | 200 ++++++++++++++++++ .../tests/per_provider/normal_tests/mod.rs | 1 + src/back/backend_handler.rs | 18 ++ .../mbed_provider/asym_encryption.rs | 88 ++++++++ src/providers/mbed_provider/asym_sign.rs | 7 +- src/providers/mbed_provider/key_management.rs | 12 +- src/providers/mbed_provider/mod.rs | 28 ++- src/providers/mod.rs | 25 ++- src/providers/pkcs11_provider/asym_sign.rs | 4 - .../pkcs11_provider/key_management.rs | 8 - 15 files changed, 520 insertions(+), 48 deletions(-) create mode 100644 e2e_tests/tests/per_provider/normal_tests/asym_encryption.rs create mode 100644 src/providers/mbed_provider/asym_encryption.rs diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 1a36747a..f783948a 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -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) diff --git a/Cargo.lock b/Cargo.lock index 1b6605b3..1d7e8df9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -213,9 +213,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.56" +version = "1.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77c1f1d60091c1b73e2b1f4560ab419204b178e625fa945ded7b660becd2bd46" +checksum = "0fde55d2a2bfaa4c9668bbc63f531fbdeee3ffe188f4662511ce2c22b3eedebe" [[package]] name = "cexpr" @@ -439,9 +439,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.1.14" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9586eedd4ce6b3c498bc3b4dd92fc9f11166aa908a914071953768066c67909" +checksum = "3deed196b6e7f9e44a2ae8d94225d80302d81208b1bb673fd21fe634645c85a9" dependencies = [ "libc", ] @@ -757,9 +757,9 @@ checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" [[package]] name = "parsec-interface" -version = "0.17.0" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3db0d49816455026327f6377243442645a590423fa1cca4978cd869f34a383a9" +checksum = "09289310e1dfe55d804e4a3be12c8fe170239e6129ffd8e8b5007078b30c6098" dependencies = [ "arbitrary", "bincode", @@ -994,20 +994,21 @@ dependencies = [ [[package]] name = "psa-crypto" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6fa12271d1af1f3267c176d8c2d28d94cf6fbfe3368fa18ecba1f8a6d083757" +checksum = "640ff8940a8a8f85c4bf8e6f1cd5adb9d26461b598f99c8217d343b27da24cd7" dependencies = [ "log", "psa-crypto-sys", "serde", + "zeroize", ] [[package]] name = "psa-crypto-sys" -version = "0.2.1" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d8e707688eb8c0fd95a0441180beacf3e4d2909f9172d6c43d10145edd5d730" +checksum = "8ab13137181ea1aead63adb3f0e44cef57e70804280f2b9b7f47e0f2d0ceb437" dependencies = [ "bindgen", "cc", diff --git a/Cargo.toml b/Cargo.toml index e72ea801..5140f7ea 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,7 +18,7 @@ name = "parsec" path = "src/bin/main.rs" [dependencies] -parsec-interface = "0.17.0" +parsec-interface = "0.18.0" rand = { version = "0.7.2", features = ["small_rng"] } base64 = "0.10.1" uuid = "0.7.4" @@ -40,7 +40,7 @@ derivative = "2.1.1" version = "3.0.0" hex = "0.4.2" picky = "5.0.0" -psa-crypto = { version = "0.2.1" , default-features = false, features = ["with-mbed-crypto"], optional = true } +psa-crypto = { version = "0.2.2" , default-features = false, features = ["with-mbed-crypto"], optional = true } zeroize = { version = "1.1.0", features = ["zeroize_derive"] } picky-asn1-x509 = { version = "0.1.0", optional = true } diff --git a/e2e_tests/Cargo.toml b/e2e_tests/Cargo.toml index e9e07b06..d19b8c21 100644 --- a/e2e_tests/Cargo.toml +++ b/e2e_tests/Cargo.toml @@ -25,4 +25,6 @@ rand = "0.7.3" [dev-dependencies] env_logger = "0.7.1" uuid = "0.7.4" -picky-asn1-x509 = "0.1.0" \ No newline at end of file +rsa = "0.3.0" +picky-asn1-x509 = "0.1.0" +base64 = "0.12.3" diff --git a/e2e_tests/src/lib.rs b/e2e_tests/src/lib.rs index 70924de3..9d07c423 100644 --- a/e2e_tests/src/lib.rs +++ b/e2e_tests/src/lib.rs @@ -14,7 +14,7 @@ use parsec_client::auth::AuthenticationData; use parsec_client::core::basic_client::BasicClient; use parsec_client::core::interface::operations::list_providers::ProviderInfo; use parsec_client::core::interface::operations::psa_algorithm::{ - Algorithm, AsymmetricSignature, Hash, + Algorithm, AsymmetricEncryption, AsymmetricSignature, Hash, }; use parsec_client::core::interface::operations::psa_key_attributes::{ Attributes, Lifetime, Policy, Type, UsageFlags, @@ -79,6 +79,12 @@ impl TestClient { ProviderID::Core } + pub fn is_operation_supported(&mut self, op: Opcode) -> bool { + self.list_opcodes(self.provider().unwrap()) + .unwrap() + .contains(&op) + } + /// Manually set the provider to execute the requests. pub fn set_provider(&mut self, provider: ProviderID) { self.basic_client.set_implicit_provider(provider); @@ -158,6 +164,64 @@ impl TestClient { ) } + pub fn generate_rsa_encryption_keys_rsapkcs1v15crypt( + &mut self, + key_name: String, + ) -> Result<()> { + self.generate_key( + key_name, + Attributes { + lifetime: Lifetime::Persistent, + key_type: Type::RsaKeyPair, + bits: 1024, + policy: Policy { + usage_flags: UsageFlags { + sign_hash: false, + verify_hash: false, + sign_message: false, + verify_message: false, + export: true, + encrypt: true, + decrypt: true, + cache: false, + copy: false, + derive: false, + }, + permitted_algorithms: AsymmetricEncryption::RsaPkcs1v15Crypt.into(), + }, + }, + ) + } + + pub fn generate_rsa_encryption_keys_rsaoaep_sha256(&mut self, key_name: String) -> Result<()> { + self.generate_key( + key_name, + Attributes { + lifetime: Lifetime::Persistent, + key_type: Type::RsaKeyPair, + bits: 1024, + policy: Policy { + usage_flags: UsageFlags { + sign_hash: false, + verify_hash: false, + sign_message: false, + verify_message: false, + export: true, + encrypt: true, + decrypt: true, + cache: false, + copy: false, + derive: false, + }, + permitted_algorithms: AsymmetricEncryption::RsaOaep { + hash_alg: Hash::Sha256, + } + .into(), + }, + }, + ) + } + /// Imports and creates a key with specific attributes. pub fn import_key( &mut self, @@ -179,7 +243,36 @@ impl TestClient { Ok(()) } - /// Import a 1024 bits RSA public key. + /// Import a 1024 bit RSA key pair + /// The key pair can only be used for encryption and decryption with RSA PKCS 1v15 + pub fn import_rsa_key_pair(&mut self, key_name: String, data: Vec) -> Result<()> { + self.import_key( + key_name, + Attributes { + lifetime: Lifetime::Persistent, + key_type: Type::RsaKeyPair, + bits: 1024, + policy: Policy { + usage_flags: UsageFlags { + sign_hash: false, + verify_hash: false, + sign_message: false, + verify_message: true, + export: false, + encrypt: true, + decrypt: true, + cache: false, + copy: false, + derive: false, + }, + permitted_algorithms: AsymmetricEncryption::RsaPkcs1v15Crypt.into(), + }, + }, + data, + ) + } + + /// Import a 1024 bit RSA public key. /// The key can only be used for verifying with the RSA PKCS 1v15 signing algorithm with SHA-256. pub fn import_rsa_public_key(&mut self, key_name: String, data: Vec) -> Result<()> { self.import_key( @@ -288,6 +381,56 @@ impl TestClient { ) } + pub fn asymmetric_encrypt_message_with_rsapkcs1v15( + &mut self, + key_name: String, + plaintext: Vec, + ) -> Result> { + self.asymmetric_encrypt_message( + key_name, + AsymmetricEncryption::RsaPkcs1v15Crypt, + &plaintext, + None, + ) + } + + pub fn asymmetric_decrypt_message_with_rsapkcs1v15( + &mut self, + key_name: String, + ciphertext: Vec, + ) -> Result> { + self.asymmetric_decrypt_message( + key_name, + AsymmetricEncryption::RsaPkcs1v15Crypt, + &ciphertext, + None, + ) + } + + pub fn asymmetric_encrypt_message( + &mut self, + key_name: String, + encryption_alg: AsymmetricEncryption, + plaintext: &[u8], + salt: Option<&[u8]>, + ) -> Result> { + self.basic_client + .psa_asymmetric_encrypt(key_name, encryption_alg, &plaintext, salt) + .map_err(convert_error) + } + + pub fn asymmetric_decrypt_message( + &mut self, + key_name: String, + encryption_alg: AsymmetricEncryption, + ciphertext: &[u8], + salt: Option<&[u8]>, + ) -> Result> { + self.basic_client + .psa_asymmetric_decrypt(key_name, encryption_alg, &ciphertext, salt) + .map_err(convert_error) + } + /// Lists the provider available for the Parsec service. pub fn list_providers(&mut self) -> Result> { self.basic_client.list_providers().map_err(convert_error) diff --git a/e2e_tests/tests/per_provider/normal_tests/asym_encryption.rs b/e2e_tests/tests/per_provider/normal_tests/asym_encryption.rs new file mode 100644 index 00000000..cc19429b --- /dev/null +++ b/e2e_tests/tests/per_provider/normal_tests/asym_encryption.rs @@ -0,0 +1,200 @@ +// Copyright 2020 Contributors to the Parsec project. +// SPDX-License-Identifier: Apache-2.0 +use e2e_tests::TestClient; +use parsec_client::core::interface::requests::{Opcode, ResponseStatus}; +use rand::rngs::OsRng; +use rsa::{PaddingScheme, PublicKey, RSAPublicKey}; + +const PLAINTEXT_MESSAGE: [u8; 32] = [ + 0x69, 0x3E, 0xDB, 0x1B, 0x22, 0x79, 0x03, 0xF4, 0xC0, 0xBF, 0xD6, 0x91, 0x76, 0x37, 0x84, 0xA2, + 0x94, 0x8E, 0x92, 0x50, 0x35, 0xC2, 0x8C, 0x5C, 0x3C, 0xCA, 0xFE, 0x18, 0xE8, 0x81, 0x37, 0x78, +]; + +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=="; + +#[allow(dead_code)] +const PUBLIC_KEY: &str = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCd+EKeRmZCKLmg7LasWqpKA9/0\ +1linY75ujilf6v/Kb8UP9r/EcO75Pvi2YPnYhBadmVOVxMOqS2zmKm1a9VTegT8d\ +N9Unf2s2KbKrKXupaQTXcrGGSB/BmHeWeiqidEMw7i9ysjHK4KEuacmYmZpvKAnN\ +WMyvQgjGgGNpsNzqawIDAQAB"; + +const ENCRYPTED_MESSAGE: &str = +"ebr0Q/lPf+905a66RjABlZJ8Xl9ZpTHrwVAHd1+sKOT0G4uCUd+q2mpKGljODiMn5gvMj8aMjTOZUROBmrZQpCnB8GCqpGtEOjJtpJy5AdfMTK+QZVvTnvEia1NTjYIoRNCSfFXTQP/ZsAfq2ViiymqwYXM270pHxS3TvBdQH9A="; + +const ORIGINAL_MESSAGE: &str = "This is a test!"; + +#[test] +fn simple_asym_encrypt_rsa_pkcs() { + let key_name = String::from("asym_encrypt_and_decrypt_rsa_pkcs"); + let mut client = TestClient::new(); + + if !client.is_operation_supported(Opcode::PsaAsymmetricEncrypt) { + return; + } + + client + .generate_rsa_encryption_keys_rsapkcs1v15crypt(key_name.clone()) + .unwrap(); + let _ciphertext = client + .asymmetric_encrypt_message_with_rsapkcs1v15(key_name.clone(), PLAINTEXT_MESSAGE.to_vec()) + .unwrap(); +} + +#[test] +fn asym_encrypt_no_key() { + let key_name = String::from("asym_encrypt_no_key"); + let mut client = TestClient::new(); + + if !client.is_operation_supported(Opcode::PsaAsymmetricEncrypt) { + return; + } + + let status = client + .asymmetric_encrypt_message_with_rsapkcs1v15(key_name, PLAINTEXT_MESSAGE.to_vec()) + .expect_err("Key should not exist."); + assert_eq!(status, ResponseStatus::PsaErrorDoesNotExist); +} + +#[test] +fn asym_decrypt_no_key() { + let key_name = String::from("asym_decrypt_no_key"); + let mut client = TestClient::new(); + + if !client.is_operation_supported(Opcode::PsaAsymmetricDecrypt) { + return; + } + + let status = client + .asymmetric_decrypt_message_with_rsapkcs1v15(key_name, PLAINTEXT_MESSAGE.to_vec()) + .expect_err("Key should not exist."); + assert_eq!(status, ResponseStatus::PsaErrorDoesNotExist); +} + +#[test] +fn asym_encrypt_wrong_algorithm() { + let key_name = String::from("asym_encrypt_wrong_algorithm"); + let mut client = TestClient::new(); + + if !client.is_operation_supported(Opcode::PsaAsymmetricEncrypt) { + return; + } + + let _key_id = client + .generate_rsa_encryption_keys_rsaoaep_sha256(key_name.clone()) + .unwrap(); + let status = client + .asymmetric_encrypt_message_with_rsapkcs1v15(key_name.clone(), PLAINTEXT_MESSAGE.to_vec()) + .unwrap_err(); + assert_eq!(status, ResponseStatus::PsaErrorNotPermitted); +} + +#[test] +fn asym_encrypt_and_decrypt_rsa_pkcs() { + let key_name = String::from("asym_encrypt_and_decrypt_rsa_pkcs"); + let mut client = TestClient::new(); + + if !client.is_operation_supported(Opcode::PsaAsymmetricEncrypt) + || !client.is_operation_supported(Opcode::PsaAsymmetricDecrypt) + { + return; + } + + client + .generate_rsa_encryption_keys_rsapkcs1v15crypt(key_name.clone()) + .unwrap(); + let ciphertext = client + .asymmetric_encrypt_message_with_rsapkcs1v15(key_name.clone(), PLAINTEXT_MESSAGE.to_vec()) + .unwrap(); + let plaintext = client + .asymmetric_decrypt_message_with_rsapkcs1v15(key_name, ciphertext) + .unwrap(); + assert_eq!(PLAINTEXT_MESSAGE.to_vec(), plaintext); +} + +#[test] +fn asym_encrypt_decrypt_rsa_pkcs_different_keys() { + let key_name_1 = String::from("asym_encrypt_and_decrypt_rsa_pkcs_different_keys_1"); + let key_name_2 = String::from("asym_encrypt_and_decrypt_rsa_pkcs_different_keys_2"); + let mut client = TestClient::new(); + + if !client.is_operation_supported(Opcode::PsaAsymmetricEncrypt) + || !client.is_operation_supported(Opcode::PsaAsymmetricDecrypt) + { + return; + } + + client + .generate_rsa_encryption_keys_rsapkcs1v15crypt(key_name_1.clone()) + .unwrap(); + client + .generate_rsa_encryption_keys_rsapkcs1v15crypt(key_name_2.clone()) + .unwrap(); + let ciphertext = client + .asymmetric_encrypt_message_with_rsapkcs1v15(key_name_1.clone(), PLAINTEXT_MESSAGE.to_vec()) + .unwrap(); + let _res = client + .asymmetric_decrypt_message_with_rsapkcs1v15(key_name_2.clone(), ciphertext) + .unwrap_err(); +} + +#[test] +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(); + + if !client.is_operation_supported(Opcode::PsaAsymmetricDecrypt) { + return; + } + + 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[..]); +} + +/// Uses key pair generated online to decrypt a message that has been pre-encrypted +#[test] +fn asym_verify_decrypt_with_internet() { + let key_name = String::from("asym_derify_decrypt_with_pick"); + let mut client = TestClient::new(); + + if !client.is_operation_supported(Opcode::PsaAsymmetricDecrypt) { + return; + } + + client + .import_rsa_key_pair(key_name.clone(), base64::decode(PRIVATE_KEY).unwrap()) + .unwrap(); + let encrypt_bytes = base64::decode(ENCRYPTED_MESSAGE).unwrap(); + let plaintext_bytes = client + .asymmetric_decrypt_message_with_rsapkcs1v15(key_name, encrypt_bytes) + .unwrap(); + assert_eq!(ORIGINAL_MESSAGE.as_bytes(), plaintext_bytes.as_slice()); +} diff --git a/e2e_tests/tests/per_provider/normal_tests/mod.rs b/e2e_tests/tests/per_provider/normal_tests/mod.rs index beb4dee4..df4d38e7 100644 --- a/e2e_tests/tests/per_provider/normal_tests/mod.rs +++ b/e2e_tests/tests/per_provider/normal_tests/mod.rs @@ -1,5 +1,6 @@ // Copyright 2019 Contributors to the Parsec project. // SPDX-License-Identifier: Apache-2.0 +mod asym_encryption; mod asym_sign_verify; mod auth; mod basic; diff --git a/src/back/backend_handler.rs b/src/back/backend_handler.rs index f62582cd..b8a07547 100644 --- a/src/back/backend_handler.rs +++ b/src/back/backend_handler.rs @@ -159,6 +159,24 @@ impl BackEndHandler { trace!("psa_verify_hash egress"); self.result_to_response(NativeResult::PsaVerifyHash(result), header) } + NativeOperation::PsaAsymmetricEncrypt(op_asymmetric_encrypt) => { + let app_name = + unwrap_or_else_return!(app_name.ok_or(ResponseStatus::NotAuthenticated)); + let result = unwrap_or_else_return!(self + .provider + .psa_asymmetric_encrypt(app_name, op_asymmetric_encrypt)); + trace!("psa_asymmetric_encrypt_egress"); + self.result_to_response(NativeResult::PsaAsymmetricEncrypt(result), header) + } + NativeOperation::PsaAsymmetricDecrypt(op_asymmetric_decrypt) => { + let app_name = + unwrap_or_else_return!(app_name.ok_or(ResponseStatus::NotAuthenticated)); + let result = unwrap_or_else_return!(self + .provider + .psa_asymmetric_decrypt(app_name, op_asymmetric_decrypt)); + trace!("psa_asymmetric_encrypt_egress"); + self.result_to_response(NativeResult::PsaAsymmetricDecrypt(result), header) + } } } } diff --git a/src/providers/mbed_provider/asym_encryption.rs b/src/providers/mbed_provider/asym_encryption.rs new file mode 100644 index 00000000..f1b57084 --- /dev/null +++ b/src/providers/mbed_provider/asym_encryption.rs @@ -0,0 +1,88 @@ +// Copyright 2020 Contributors to the Parsec project. +// SPDX-License-Identifier: Apache-2.0 +use super::{key_management, MbedProvider}; +use crate::authenticators::ApplicationName; +use crate::key_info_managers::KeyTriple; +use parsec_interface::operations::{psa_asymmetric_decrypt, psa_asymmetric_encrypt}; +use parsec_interface::requests::{ProviderID, ResponseStatus, Result}; +use psa_crypto::operations::asym_encryption; +use psa_crypto::types::key; + +impl MbedProvider { + pub(super) fn psa_asymmetric_encrypt_internal( + &self, + app_name: ApplicationName, + op: psa_asymmetric_encrypt::Operation, + ) -> Result { + let key_name = op.key_name.clone(); + + let key_triple = KeyTriple::new(app_name, ProviderID::MbedCrypto, key_name); + let store_handle = self.key_info_store.read().expect("Key store lock poisoned"); + let key_id = key_management::get_key_id(&key_triple, &*store_handle)?; + let _guard = self + .key_handle_mutex + .lock() + .expect("Grabbing key handle mutex failed"); + let id = key::Id::from_persistent_key_id(key_id); + let key_attributes = key::Attributes::from_key_id(id)?; + + op.validate(key_attributes)?; + let salt_buff = op.salt.as_ref().map(|salt| salt.as_slice()); + let alg = op.alg; + let buffer_size = key_attributes.asymmetric_encrypt_output_size(alg)?; + let mut ciphertext = vec![0u8; buffer_size]; + + match asym_encryption::encrypt(id, alg, &op.plaintext, salt_buff, &mut ciphertext) { + Ok(output_size) => { + ciphertext.resize(output_size, 0); + Ok(psa_asymmetric_encrypt::Result { + ciphertext: ciphertext.into(), + }) + } + Err(error) => { + let error = ResponseStatus::from(error); + format_error!("Encrypt status: ", error); + Err(error) + } + } + } + + pub(super) fn psa_asymmetric_decrypt_internal( + &self, + app_name: ApplicationName, + op: psa_asymmetric_decrypt::Operation, + ) -> Result { + let key_triple = KeyTriple::new(app_name, ProviderID::MbedCrypto, op.key_name.clone()); + let store_handle = self.key_info_store.read().expect("Key store lock poisoned"); + let key_id = key_management::get_key_id(&key_triple, &*store_handle)?; + + let _guard = self + .key_handle_mutex + .lock() + .expect("Grabbing key handle mutex failed"); + + let id = key::Id::from_persistent_key_id(key_id); + let key_attributes = key::Attributes::from_key_id(id)?; + op.validate(key_attributes)?; + let salt_buff = match &op.salt { + Some(salt) => Some(salt.as_slice()), + None => None, + }; + let buffer_size = key_attributes.asymmetric_decrypt_output_size(op.alg)?; + let mut plaintext = vec![0u8; buffer_size]; + + match asym_encryption::decrypt(id, op.alg, &op.ciphertext, salt_buff, &mut plaintext) { + Ok(output_size) => { + plaintext.resize(output_size, 0); + Ok(psa_asymmetric_decrypt::Result { + plaintext: plaintext.into(), + }) + } + Err(error) => { + let error = ResponseStatus::from(error); + format_error!("Decrypt status: ", error); + Err(error) + } + } + } +} diff --git a/src/providers/mbed_provider/asym_sign.rs b/src/providers/mbed_provider/asym_sign.rs index ef60c7fa..be4b5119 100644 --- a/src/providers/mbed_provider/asym_sign.rs +++ b/src/providers/mbed_provider/asym_sign.rs @@ -3,7 +3,6 @@ use super::{key_management, MbedProvider}; use crate::authenticators::ApplicationName; use crate::key_info_managers::KeyTriple; -use log::info; use parsec_interface::operations::{psa_sign_hash, psa_verify_hash}; use parsec_interface::requests::{ProviderID, ResponseStatus, Result}; use psa_crypto::operations::asym_signature; @@ -15,7 +14,6 @@ impl MbedProvider { app_name: ApplicationName, op: psa_sign_hash::Operation, ) -> Result { - info!("Mbed Provider - Asym Sign"); let key_name = op.key_name; let hash = op.hash; let alg = op.alg; @@ -42,7 +40,7 @@ impl MbedProvider { } Err(error) => { let error = ResponseStatus::from(error); - format_error!("Sign status: {}", error); + format_error!("Sign status: ", error); Err(error) } } @@ -53,7 +51,6 @@ impl MbedProvider { app_name: ApplicationName, op: psa_verify_hash::Operation, ) -> Result { - info!("Mbed Provider - Asym Verify"); let key_name = op.key_name; let hash = op.hash; let alg = op.alg; @@ -72,7 +69,7 @@ impl MbedProvider { Ok(()) => Ok(psa_verify_hash::Result {}), Err(error) => { let error = ResponseStatus::from(error); - format_error!("Verify status: {}", error); + format_error!("Verify status: ", error); Err(error) } } diff --git a/src/providers/mbed_provider/key_management.rs b/src/providers/mbed_provider/key_management.rs index d87dfacc..75e1cc2e 100644 --- a/src/providers/mbed_provider/key_management.rs +++ b/src/providers/mbed_provider/key_management.rs @@ -5,7 +5,7 @@ use crate::authenticators::ApplicationName; use crate::key_info_managers; use crate::key_info_managers::{KeyInfo, KeyTriple, ManageKeyInfo}; use log::error; -use log::{info, warn}; +use log::warn; use parsec_interface::operations::psa_key_attributes::Attributes; use parsec_interface::operations::{ psa_destroy_key, psa_export_public_key, psa_generate_key, psa_import_key, @@ -97,7 +97,6 @@ impl MbedProvider { app_name: ApplicationName, op: psa_generate_key::Operation, ) -> Result { - info!("Mbed Provider - Create Key"); let key_name = op.key_name; let key_attributes = op.attributes; let key_triple = KeyTriple::new(app_name, ProviderID::MbedCrypto, key_name); @@ -125,7 +124,7 @@ impl MbedProvider { Err(error) => { remove_key_id(&key_triple, &mut *store_handle)?; let error = ResponseStatus::from(error); - format_error!("Generate key status: {}", error); + format_error!("Generate key status: ", error); Err(error) } } @@ -136,7 +135,6 @@ impl MbedProvider { app_name: ApplicationName, op: psa_import_key::Operation, ) -> Result { - info!("Mbed Provider - Import Key"); let key_name = op.key_name; let key_attributes = op.attributes; let key_data = op.data; @@ -169,7 +167,7 @@ impl MbedProvider { Err(error) => { remove_key_id(&key_triple, &mut *store_handle)?; let error = ResponseStatus::from(error); - format_error!("Import key status: {}", error); + format_error!("Import key status: ", error); Err(error) } } @@ -180,7 +178,6 @@ impl MbedProvider { app_name: ApplicationName, op: psa_export_public_key::Operation, ) -> Result { - info!("Mbed Provider - Export Public Key"); let key_name = op.key_name; let key_triple = KeyTriple::new(app_name, ProviderID::MbedCrypto, key_name); let store_handle = self.key_info_store.read().expect("Key store lock poisoned"); @@ -209,7 +206,6 @@ impl MbedProvider { app_name: ApplicationName, op: psa_destroy_key::Operation, ) -> Result { - info!("Mbed Provider - Destroy Key"); let key_name = op.key_name; let key_triple = KeyTriple::new(app_name, ProviderID::MbedCrypto, key_name); let mut store_handle = self @@ -240,7 +236,7 @@ impl MbedProvider { } Err(error) => { let error = ResponseStatus::from(error); - format_error!("Destroy key status: {}", error); + format_error!("Destroy key status: ", error); Err(error) } } diff --git a/src/providers/mbed_provider/mod.rs b/src/providers/mbed_provider/mod.rs index 41a555d8..374da84c 100644 --- a/src/providers/mbed_provider/mod.rs +++ b/src/providers/mbed_provider/mod.rs @@ -7,8 +7,8 @@ use derivative::Derivative; use log::{error, trace}; use parsec_interface::operations::list_providers::ProviderInfo; use parsec_interface::operations::{ - psa_destroy_key, psa_export_public_key, psa_generate_key, psa_import_key, psa_sign_hash, - psa_verify_hash, + psa_asymmetric_decrypt, psa_asymmetric_encrypt, psa_destroy_key, psa_export_public_key, + psa_generate_key, psa_import_key, psa_sign_hash, psa_verify_hash, }; use parsec_interface::requests::{Opcode, ProviderID, ResponseStatus, Result}; use psa_crypto::types::{key, status}; @@ -20,6 +20,7 @@ use std::sync::{ }; use uuid::Uuid; +mod asym_encryption; mod asym_sign; #[allow(dead_code)] mod key_management; @@ -104,10 +105,7 @@ impl MbedProvider { } Err(status::Error::DoesNotExist) => to_remove.push(key_triple.clone()), Err(e) => { - format_error!( - "Error {} when opening a persistent Mbed Crypto key.", - e - ); + format_error!("Failed to open persistent Mbed Crypto key", e); return None; } }; @@ -198,6 +196,24 @@ impl Provide for MbedProvider { trace!("psa_verify_hash ingress"); self.psa_verify_hash_internal(app_name, op) } + + fn psa_asymmetric_encrypt( + &self, + app_name: ApplicationName, + op: psa_asymmetric_encrypt::Operation, + ) -> Result { + trace!("psa_asymmetric_encrypt ingress"); + self.psa_asymmetric_encrypt_internal(app_name, op) + } + + fn psa_asymmetric_decrypt( + &self, + app_name: ApplicationName, + op: psa_asymmetric_decrypt::Operation, + ) -> Result { + trace!("psa_asymmetric_decrypt ingress"); + self.psa_asymmetric_decrypt_internal(app_name, op) + } } #[derive(Default, Derivative)] diff --git a/src/providers/mod.rs b/src/providers/mod.rs index 43dca64b..62f1633f 100644 --- a/src/providers/mod.rs +++ b/src/providers/mod.rs @@ -75,8 +75,9 @@ impl ProviderConfig { use crate::authenticators::ApplicationName; use parsec_interface::operations::{ - list_opcodes, list_providers, ping, psa_destroy_key, psa_export_public_key, psa_generate_key, - psa_import_key, psa_sign_hash, psa_verify_hash, + list_opcodes, list_providers, ping, psa_asymmetric_decrypt, psa_asymmetric_encrypt, + psa_destroy_key, psa_export_public_key, psa_generate_key, psa_import_key, psa_sign_hash, + psa_verify_hash, }; use parsec_interface::requests::{ResponseStatus, Result}; @@ -176,4 +177,24 @@ pub trait Provide { trace!("psa_verify_hash ingress"); Err(ResponseStatus::PsaErrorNotSupported) } + + /// Execute an AsymmetricEncrypt operation. + fn psa_asymmetric_encrypt( + &self, + _app_name: ApplicationName, + _op: psa_asymmetric_encrypt::Operation, + ) -> Result { + trace!("psa_asymmetric_encrypt ingress"); + Err(ResponseStatus::PsaErrorNotSupported) + } + + /// Execute an AsymmetricDecrypt operation. + fn psa_asymmetric_decrypt( + &self, + _app_name: ApplicationName, + _op: psa_asymmetric_decrypt::Operation, + ) -> Result { + trace!("psa_asymmetric_decrypt ingress"); + Err(ResponseStatus::PsaErrorNotSupported) + } } diff --git a/src/providers/pkcs11_provider/asym_sign.rs b/src/providers/pkcs11_provider/asym_sign.rs index 6a25abeb..37ac6f26 100644 --- a/src/providers/pkcs11_provider/asym_sign.rs +++ b/src/providers/pkcs11_provider/asym_sign.rs @@ -25,8 +25,6 @@ impl Pkcs11Provider { app_name: ApplicationName, op: psa_sign_hash::Operation, ) -> Result { - info!("Pkcs11 Provider - Asym Sign"); - let key_name = op.key_name; let hash = op.hash; let alg = op.alg; @@ -113,8 +111,6 @@ impl Pkcs11Provider { app_name: ApplicationName, op: psa_verify_hash::Operation, ) -> Result { - info!("Pkcs11 Provider - Asym Verify"); - let key_name = op.key_name; let hash = op.hash; let signature = op.signature; diff --git a/src/providers/pkcs11_provider/key_management.rs b/src/providers/pkcs11_provider/key_management.rs index 7c7c00e1..f1fc6717 100644 --- a/src/providers/pkcs11_provider/key_management.rs +++ b/src/providers/pkcs11_provider/key_management.rs @@ -145,8 +145,6 @@ impl Pkcs11Provider { app_name: ApplicationName, op: psa_generate_key::Operation, ) -> Result { - info!("Pkcs11 Provider - Create Key"); - if op.attributes.key_type != Type::RsaKeyPair { error!("The PKCS11 provider currently only supports creating RSA key pairs."); return Err(ResponseStatus::PsaErrorNotSupported); @@ -248,8 +246,6 @@ impl Pkcs11Provider { app_name: ApplicationName, op: psa_import_key::Operation, ) -> Result { - info!("Pkcs11 Provider - Import Key"); - if op.attributes.key_type != Type::RsaPublicKey { error!("The PKCS 11 provider currently only supports importing RSA public key."); return Err(ResponseStatus::PsaErrorNotSupported); @@ -390,8 +386,6 @@ impl Pkcs11Provider { app_name: ApplicationName, op: psa_export_public_key::Operation, ) -> Result { - info!("Pkcs11 Provider - Export Public Key"); - let key_name = op.key_name; let key_triple = KeyTriple::new(app_name, ProviderID::Pkcs11, key_name); let store_handle = self.key_info_store.read().expect("Key store lock poisoned"); @@ -488,8 +482,6 @@ impl Pkcs11Provider { app_name: ApplicationName, op: psa_destroy_key::Operation, ) -> Result { - info!("Pkcs11 Provider - Destroy Key"); - let key_name = op.key_name; let key_triple = KeyTriple::new(app_name, ProviderID::Pkcs11, key_name); let mut store_handle = self