From 0a6b0e580439a7ad943c1433f17230347a86653a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Jeli=C4=87?= Date: Wed, 20 Jan 2021 16:27:59 +0100 Subject: [PATCH] base: Properly handle crypto related errors in the sled store --- matrix_sdk_base/src/store/mod.rs | 17 +++--- matrix_sdk_base/src/store/sled_store/mod.rs | 52 ++++++++++++++----- .../src/store/sled_store/store_key.rs | 9 ++-- 3 files changed, 51 insertions(+), 27 deletions(-) diff --git a/matrix_sdk_base/src/store/mod.rs b/matrix_sdk_base/src/store/mod.rs index 1448409b..196aaf48 100644 --- a/matrix_sdk_base/src/store/mod.rs +++ b/matrix_sdk_base/src/store/mod.rs @@ -25,8 +25,6 @@ use matrix_sdk_common::{ locks::RwLock, }; -use sled::transaction::TransactionError; - use crate::{ deserialized_responses::{MemberEvent, StrippedMemberEvent}, rooms::{RoomInfo, RoomType, StrippedRoom}, @@ -44,15 +42,12 @@ pub enum StoreError { Json(#[from] serde_json::Error), #[error(transparent)] Identifier(#[from] matrix_sdk_common::identifiers::Error), -} - -impl From> for StoreError { - fn from(e: TransactionError) -> Self { - match e { - TransactionError::Abort(e) => Self::Json(e), - TransactionError::Storage(e) => Self::Sled(e), - } - } + #[error("The store failed to be unlocked")] + StoreLocked, + #[error("The store is not encrypted but was tried to be opened with a passphrase")] + UnencryptedStore, + #[error("Error encrypting or decrypting data from the store: {0}")] + Encryption(String), } /// A `StateStore` specific result type. diff --git a/matrix_sdk_base/src/store/sled_store/mod.rs b/matrix_sdk_base/src/store/sled_store/mod.rs index e0a94546..05c5df36 100644 --- a/matrix_sdk_base/src/store/sled_store/mod.rs +++ b/matrix_sdk_base/src/store/sled_store/mod.rs @@ -45,6 +45,35 @@ pub enum DatabaseType { Encrypted(store_key::EncryptedStoreKey), } +#[derive(Debug, thiserror::Error)] +pub enum SerializationError { + #[error(transparent)] + Json(#[from] serde_json::Error), + #[error(transparent)] + Encryption(#[from] store_key::Error), +} + +impl From> for StoreError { + fn from(e: TransactionError) -> Self { + match e { + TransactionError::Abort(e) => e.into(), + TransactionError::Storage(e) => StoreError::Sled(e), + } + } +} + +impl From for StoreError { + fn from(e: SerializationError) -> Self { + match e { + SerializationError::Json(e) => StoreError::Json(e), + SerializationError::Encryption(e) => match e { + store_key::Error::Serialization(e) => StoreError::Json(e), + store_key::Error::Encryption(e) => StoreError::Encryption(e), + }, + } + } +} + #[derive(Debug, Clone)] pub struct SledStore { inner: Db, @@ -119,10 +148,9 @@ impl SledStore { let store_key = if let Some(key) = store_key { if let DatabaseType::Encrypted(k) = key { - let key = StoreKey::import(passphrase, k).unwrap(); - key + StoreKey::import(passphrase, k).map_err(|_| StoreError::StoreLocked)? } else { - panic!("Trying to open an unencrypted store with a passphrase"); + return Err(StoreError::UnencryptedStore); } } else { let key = StoreKey::new(); @@ -144,24 +172,24 @@ impl SledStore { fn serialize_event( &self, event: &impl Serialize, - ) -> std::result::Result, serde_json::Error> { + ) -> std::result::Result, SerializationError> { if let Some(key) = &*self.store_key { - let encrypted = key.encrypt(event).unwrap(); - serde_json::to_vec(&encrypted) + let encrypted = key.encrypt(event)?; + Ok(serde_json::to_vec(&encrypted)?) } else { - serde_json::to_vec(event) + Ok(serde_json::to_vec(event)?) } } fn deserialize_event Deserialize<'b>>( &self, event: &[u8], - ) -> std::result::Result { + ) -> std::result::Result { if let Some(key) = &*self.store_key { let encrypted: EncryptedEvent = serde_json::from_slice(&event)?; - Ok(key.decrypt(encrypted).unwrap()) + Ok(key.decrypt(encrypted)?) } else { - serde_json::from_slice(event) + Ok(serde_json::from_slice(event)?) } } @@ -189,7 +217,7 @@ impl SledStore { pub async fn save_changes(&self, changes: &StateChanges) -> Result<()> { let now = SystemTime::now(); - let ret: std::result::Result<(), TransactionError> = ( + let ret: std::result::Result<(), TransactionError> = ( &self.session, &self.account_data, &self.members, @@ -440,7 +468,7 @@ impl SledStore { stream::iter( self.room_info .iter() - .map(move |r| db.deserialize_event(&r?.1).map_err(StoreError::Json)), + .map(move |r| db.deserialize_event(&r?.1).map_err(|e| e.into())), ) } } diff --git a/matrix_sdk_base/src/store/sled_store/store_key.rs b/matrix_sdk_base/src/store/sled_store/store_key.rs index 3a11841a..27ac5886 100644 --- a/matrix_sdk_base/src/store/sled_store/store_key.rs +++ b/matrix_sdk_base/src/store/sled_store/store_key.rs @@ -44,8 +44,6 @@ pub enum Error { Serialization(#[from] serde_json::Error), #[error("Error encrypting or decrypting an event {0}")] Encryption(String), - #[error("Unknown ciphertext version")] - InvalidVersion, } impl From for Error { @@ -129,6 +127,7 @@ impl StoreKey { Default::default() } + /// Expand the given passphrase into a KEY_SIZE long key. fn expand_key(passphrase: &str, salt: &[u8], rounds: u32) -> Zeroizing> { let mut key = Zeroizing::from(vec![0u8; KEY_SIZE]); pbkdf2::>(passphrase.as_bytes(), &salt, rounds, &mut *key); @@ -172,7 +171,7 @@ impl StoreKey { fn get_nonce() -> Vec { let mut nonce = vec![0u8; XNONCE_SIZE]; - getrandom(&mut nonce).expect("Can't generate nonce"); + getrandom(&mut nonce).expect("Can't get random nonce"); nonce } @@ -194,7 +193,9 @@ impl StoreKey { pub fn decrypt Deserialize<'b>>(&self, event: EncryptedEvent) -> Result { if event.version != VERSION { - return Err(Error::InvalidVersion); + return Err(Error::Encryption( + "Error decrypting: Unknown ciphertext version".to_string(), + )); } let cipher = XChaCha20Poly1305::new(self.key());