From f13d3b63c6bd5b77bd1ae8c55fb2e332da327f85 Mon Sep 17 00:00:00 2001 From: Edmund Grimley Evans Date: Wed, 26 Jan 2022 11:54:17 +0000 Subject: [PATCH] Make psa_crypto thread-safe with a global lock. Current implementations of the C library, Mbed TLS, are not thread-safe, but Rust crates are expected to be thread-safe, so we add a global read/write lock; psa_crypto functions that use keys obtain an appropriate lock. Signed-off-by: Edmund Grimley Evans --- psa-crypto/Cargo.toml | 1 + psa-crypto/src/lib.rs | 6 ++++++ psa-crypto/src/operations/aead.rs | 3 +++ psa-crypto/src/operations/asym_encryption.rs | 3 +++ psa-crypto/src/operations/asym_signature.rs | 3 +++ psa-crypto/src/operations/hash.rs | 3 +++ psa-crypto/src/operations/key_agreement.rs | 3 +++ psa-crypto/src/operations/key_derivation.rs | 2 ++ psa-crypto/src/operations/key_management.rs | 12 ++++++++++-- psa-crypto/src/operations/mac.rs | 6 ++++-- psa-crypto/src/operations/other.rs | 2 ++ psa-crypto/src/types/key.rs | 3 +++ 12 files changed, 43 insertions(+), 4 deletions(-) diff --git a/psa-crypto/Cargo.toml b/psa-crypto/Cargo.toml index 9c42a71..a5f871b 100644 --- a/psa-crypto/Cargo.toml +++ b/psa-crypto/Cargo.toml @@ -13,6 +13,7 @@ repository = "https://github.com/parallaxsecond/rust-psa-crypto" [dependencies] psa-crypto-sys = { path = "../psa-crypto-sys", version = "0.9.0", default-features = false } log = "0.4.11" +parking_lot = "0.11.2" serde = { version = "1.0.115", features = ["derive"] } # Versions 1.4.x no longer compiles with Rust version 1.46.0 zeroize = { version = "<=1.3.0", features = ["zeroize_derive"] } diff --git a/psa-crypto/src/lib.rs b/psa-crypto/src/lib.rs index 6081097..3e30c36 100644 --- a/psa-crypto/src/lib.rs +++ b/psa-crypto/src/lib.rs @@ -73,6 +73,7 @@ static INITIALISED: AtomicBool = AtomicBool::new(false); #[cfg(feature = "operations")] pub fn init() -> Result<()> { // It is not a problem to call psa_crypto_init more than once. + let _lock = LOCK.write(); Status::from(unsafe { psa_crypto_sys::psa_crypto_init() }).to_result()?; let _ = INITIALISED.store(true, Ordering::Relaxed); @@ -96,3 +97,8 @@ pub fn initialized() -> Result<()> { Err(Error::BadState) } } + +#[cfg(feature = "operations")] +use parking_lot::{const_rwlock, RwLock}; +#[cfg(feature = "operations")] +static LOCK: RwLock<()> = const_rwlock(()); diff --git a/psa-crypto/src/operations/aead.rs b/psa-crypto/src/operations/aead.rs index f3d065b..7ead779 100644 --- a/psa-crypto/src/operations/aead.rs +++ b/psa-crypto/src/operations/aead.rs @@ -9,6 +9,7 @@ use crate::initialized; use crate::types::algorithm::Aead; use crate::types::key::Id; use crate::types::status::{Result, Status}; +use crate::LOCK; /// Process an authenticated encryption operation. /// # Example @@ -51,6 +52,7 @@ pub fn encrypt( ciphertext: &mut [u8], ) -> Result { initialized()?; + let _lock = LOCK.read(); let mut ciphertext_size = 0; Status::from(unsafe { @@ -113,6 +115,7 @@ pub fn decrypt( plaintext: &mut [u8], ) -> Result { initialized()?; + let _lock = LOCK.read(); let mut plaintext_size = 0; diff --git a/psa-crypto/src/operations/asym_encryption.rs b/psa-crypto/src/operations/asym_encryption.rs index 66cc232..cd21dc1 100644 --- a/psa-crypto/src/operations/asym_encryption.rs +++ b/psa-crypto/src/operations/asym_encryption.rs @@ -9,6 +9,7 @@ use crate::initialized; use crate::types::algorithm::AsymmetricEncryption; use crate::types::key::Id; use crate::types::status::{Result, Status}; +use crate::LOCK; /// Encrypt a short message with a key pair or public key /// @@ -58,6 +59,7 @@ pub fn encrypt( ciphertext: &mut [u8], ) -> Result { initialized()?; + let _lock = LOCK.read(); let mut output_length = 0; let (salt_ptr, salt_len) = match salt { @@ -139,6 +141,7 @@ pub fn decrypt( plaintext: &mut [u8], ) -> Result { initialized()?; + let _lock = LOCK.read(); let mut output_length = 0; let (salt_ptr, salt_len) = match salt { diff --git a/psa-crypto/src/operations/asym_signature.rs b/psa-crypto/src/operations/asym_signature.rs index e7bf109..de728ed 100644 --- a/psa-crypto/src/operations/asym_signature.rs +++ b/psa-crypto/src/operations/asym_signature.rs @@ -9,6 +9,7 @@ use crate::initialized; use crate::types::algorithm::AsymmetricSignature; use crate::types::key::Id; use crate::types::status::{Result, Status}; +use crate::LOCK; /// Sign an already-calculated hash with a private key /// @@ -59,6 +60,7 @@ pub fn sign_hash( signature: &mut [u8], ) -> Result { initialized()?; + let _lock = LOCK.read(); let mut signature_length = 0; @@ -119,6 +121,7 @@ pub fn sign_hash( /// ``` pub fn verify_hash(key: Id, alg: AsymmetricSignature, hash: &[u8], signature: &[u8]) -> Result<()> { initialized()?; + let _lock = LOCK.read(); Status::from(unsafe { psa_crypto_sys::psa_verify_hash( diff --git a/psa-crypto/src/operations/hash.rs b/psa-crypto/src/operations/hash.rs index 4198282..ac5db80 100644 --- a/psa-crypto/src/operations/hash.rs +++ b/psa-crypto/src/operations/hash.rs @@ -8,6 +8,7 @@ use crate::initialized; use crate::types::algorithm::Hash; use crate::types::status::{Result, Status}; +use crate::LOCK; /// Calculate hash of a message /// @@ -30,6 +31,7 @@ use crate::types::status::{Result, Status}; /// ``` pub fn hash_compute(hash_alg: Hash, input: &[u8], hash: &mut [u8]) -> Result { initialized()?; + let _lock = LOCK.read(); let mut output_length = 0; @@ -64,6 +66,7 @@ pub fn hash_compute(hash_alg: Hash, input: &[u8], hash: &mut [u8]) -> Result Result<()> { initialized()?; + let _lock = LOCK.read(); Status::from(unsafe { psa_crypto_sys::psa_hash_compare( diff --git a/psa-crypto/src/operations/key_agreement.rs b/psa-crypto/src/operations/key_agreement.rs index 2c222c4..cf9fcaf 100644 --- a/psa-crypto/src/operations/key_agreement.rs +++ b/psa-crypto/src/operations/key_agreement.rs @@ -6,6 +6,7 @@ use crate::initialized; use crate::types::algorithm::RawKeyAgreement; use crate::types::key::Id; use crate::types::status::{Result, Status}; +use crate::LOCK; /// Perform a key agreement and return the raw shared secret. /// # Example @@ -49,6 +50,8 @@ pub fn raw_key_agreement( output: &mut [u8], ) -> Result { initialized()?; + let _lock = LOCK.read(); + let mut output_size = 0; Status::from(unsafe { psa_crypto_sys::psa_raw_key_agreement( diff --git a/psa-crypto/src/operations/key_derivation.rs b/psa-crypto/src/operations/key_derivation.rs index 82380ab..56ef66b 100644 --- a/psa-crypto/src/operations/key_derivation.rs +++ b/psa-crypto/src/operations/key_derivation.rs @@ -8,6 +8,7 @@ use crate::types::key::Attributes; use crate::types::key::Id; use crate::types::key_derivation::Operation; use crate::types::status::{Error, Result, Status}; +use crate::LOCK; use core::convert::{TryFrom, TryInto}; /// This function calculates output bytes from a key derivation algorithm and uses those bytes to generate a key deterministically. @@ -65,6 +66,7 @@ use core::convert::{TryFrom, TryInto}; /// ``` pub fn output_key(operation: Operation, attributes: Attributes, id: Option) -> Result { initialized()?; + let _lock = LOCK.read(); let mut key_attributes = psa_crypto_sys::psa_key_attributes_t::try_from(attributes)?; if let Some(id) = id { diff --git a/psa-crypto/src/operations/key_management.rs b/psa-crypto/src/operations/key_management.rs index bba3084..ada851b 100644 --- a/psa-crypto/src/operations/key_management.rs +++ b/psa-crypto/src/operations/key_management.rs @@ -6,6 +6,7 @@ use crate::initialized; use crate::types::key::{Attributes, Id}; use crate::types::status::{Result, Status}; +use crate::LOCK; use core::convert::TryFrom; #[cfg(feature = "interface")] use log::error; @@ -45,6 +46,7 @@ use log::error; /// ``` pub fn generate(attributes: Attributes, id: Option) -> Result { initialized()?; + let _lock = LOCK.write(); let mut key_attributes = psa_crypto_sys::psa_key_attributes_t::try_from(attributes)?; if let Some(id) = id { unsafe { psa_crypto_sys::psa_set_key_id(&mut key_attributes, id) }; @@ -97,6 +99,7 @@ pub fn generate(attributes: Attributes, id: Option) -> Result { /// ``` pub unsafe fn destroy(key: Id) -> Result<()> { initialized()?; + let _lock = LOCK.write(); Status::from(psa_crypto_sys::psa_destroy_key(key.0)).to_result() } @@ -144,6 +147,7 @@ pub unsafe fn destroy(key: Id) -> Result<()> { /// ``` pub fn import(attributes: Attributes, id: Option, data: &[u8]) -> Result { initialized()?; + let _lock = LOCK.write(); let mut key_attributes = psa_crypto_sys::psa_key_attributes_t::try_from(attributes)?; if let Some(id) = id { @@ -194,8 +198,9 @@ pub fn import(attributes: Attributes, id: Option, data: &[u8]) -> Result Result { initialized()?; - let mut data_length = 0; + let _lock = LOCK.read(); + let mut data_length = 0; Status::from(unsafe { psa_crypto_sys::psa_export_public_key( key.0, @@ -241,8 +246,9 @@ pub fn export_public(key: Id, data: &mut [u8]) -> Result { /// ``` pub fn export(key: Id, data: &mut [u8]) -> Result { initialized()?; - let mut data_length = 0; + let _lock = LOCK.read(); + let mut data_length = 0; Status::from(unsafe { psa_crypto_sys::psa_export_key(key.0, data.as_mut_ptr(), data.len(), &mut data_length) }) @@ -281,6 +287,8 @@ pub fn export(key: Id, data: &mut [u8]) -> Result { /// ``` pub fn copy(key_id_to_copy: Id, attributes: Attributes, id: Option) -> Result { initialized()?; + let _lock = LOCK.write(); + let mut key_attributes = psa_crypto_sys::psa_key_attributes_t::try_from(attributes)?; if let Some(id) = id { unsafe { psa_crypto_sys::psa_set_key_id(&mut key_attributes, id) }; diff --git a/psa-crypto/src/operations/mac.rs b/psa-crypto/src/operations/mac.rs index 87ff6cf..a1ac681 100644 --- a/psa-crypto/src/operations/mac.rs +++ b/psa-crypto/src/operations/mac.rs @@ -7,7 +7,7 @@ use crate::initialized; use crate::types::key::Id; use crate::types::algorithm::Mac; use crate::types::status::{Result, Status, Error}; - +use crate::LOCK; /// Calculate the message authentication code (MAC) of a message /// The key must allow `sign_message` @@ -49,6 +49,7 @@ use crate::types::status::{Result, Status, Error}; /// ``` pub fn compute_mac(key_id: Id, mac_alg: Mac, input_message: &[u8], mac: &mut [u8]) -> Result { initialized()?; + let _lock = LOCK.read(); let mut output_length = 0; let key_handle = key_id.handle()?; @@ -111,6 +112,7 @@ pub fn compute_mac(key_id: Id, mac_alg: Mac, input_message: &[u8], mac: &mut [u8 /// ``` pub fn verify_mac(key_id: Id, mac_alg: Mac, input_message: &[u8], expected_mac: &[u8]) -> Result<()> { initialized()?; + let _lock = LOCK.read(); let key_handle = key_id.handle()?; @@ -127,4 +129,4 @@ pub fn verify_mac(key_id: Id, mac_alg: Mac, input_message: &[u8], expected_mac: let close_handle_res = key_id.close_handle(key_handle); mac_verify_res?; close_handle_res -} \ No newline at end of file +} diff --git a/psa-crypto/src/operations/other.rs b/psa-crypto/src/operations/other.rs index abda1ec..c924f59 100644 --- a/psa-crypto/src/operations/other.rs +++ b/psa-crypto/src/operations/other.rs @@ -7,6 +7,7 @@ use crate::initialized; use crate::types::status::{Result, Status}; +use crate::LOCK; /// Generate a buffer of random bytes. /// @@ -25,6 +26,7 @@ use crate::types::status::{Result, Status}; /// ``` pub fn generate_random(output: &mut [u8]) -> Result<()> { initialized()?; + let _lock = LOCK.read(); Status::from(unsafe { psa_crypto_sys::psa_generate_random(output.as_mut_ptr(), output.len()) }) .to_result()?; diff --git a/psa-crypto/src/types/key.rs b/psa-crypto/src/types/key.rs index 696238a..fea70fd 100644 --- a/psa-crypto/src/types/key.rs +++ b/psa-crypto/src/types/key.rs @@ -12,6 +12,8 @@ use crate::types::algorithm::{Algorithm, Cipher, KeyAgreement, RawKeyAgreement}; #[cfg(feature = "operations")] use crate::types::status::Status; use crate::types::status::{Error, Result}; +#[cfg(feature = "operations")] +use crate::LOCK; #[cfg(feature = "interface")] use core::convert::{TryFrom, TryInto}; use core::fmt; @@ -350,6 +352,7 @@ impl Attributes { #[cfg(feature = "operations")] pub fn from_key_id(key_id: Id) -> Result { initialized()?; + let _lock = LOCK.read(); let mut key_attributes = unsafe { psa_crypto_sys::psa_key_attributes_init() }; Status::from(unsafe { psa_crypto_sys::psa_get_key_attributes(key_id.0, &mut key_attributes)