crypto: Decrypt to-device events.

This commit is contained in:
Damir Jelić 2020-03-23 16:14:10 +01:00
parent 9c467d40e0
commit 4759dea9bd
5 changed files with 51 additions and 23 deletions

View file

@ -320,7 +320,7 @@ impl Client {
let mut olm = self.olm.lock().await;
if let Some(o) = &mut *olm {
o.receive_sync_response(response);
o.receive_sync_response(response).await;
}
}
}

View file

@ -13,6 +13,8 @@
// limitations under the License.
use cjson::Error as CjsonError;
use olm_rs::errors::OlmSessionError;
use serde_json::Error as SerdeError;
use thiserror::Error;
use super::store::CryptoStoreError;
@ -29,6 +31,16 @@ pub enum OlmError {
SessionWedged,
#[error("the Olm message has a unsupported type")]
UnsupportedOlmType,
#[error("the Encrypted message has been encrypted with a unsupported algorithm.")]
UnsupportedAlgorithm,
#[error("the Encrypted message doesn't contain a ciphertext for our device")]
MissingCiphertext,
#[error("can't finish Olm Session operation {0}")]
OlmSessionError(#[from] OlmSessionError),
#[error("error deserializing a string to json")]
JsonError(#[from] SerdeError),
#[error("the provided JSON value isn't an object")]
NotAnObject,
}
pub type VerificationResult<T> = std::result::Result<T, SignatureError>;

View file

@ -403,7 +403,7 @@ impl OlmMachine {
let mut matches = false;
if let OlmMessage::PreKey(m) = &message {
matches = session.matches(sender_key, m.clone()).unwrap();
matches = session.matches(sender_key, m.clone())?;
if !matches {
continue;
}
@ -429,7 +429,7 @@ impl OlmMachine {
sender: &str,
sender_key: &str,
message: OlmMessage,
) -> Result<Option<ToDeviceEvent>> {
) -> Result<EventResult<ToDeviceEvent>> {
let plaintext = if let Some(p) = self.try_decrypt_olm_event(sender_key, &message).await? {
p
} else {
@ -437,18 +437,24 @@ impl OlmMachine {
OlmMessage::Message(_) => return Err(OlmError::SessionWedged),
OlmMessage::PreKey(m) => {
let account = self.account.lock().await;
account
.create_inbound_session_from(sender_key, m.clone())
.unwrap()
account.create_inbound_session_from(sender_key, m.clone())?
}
};
session.decrypt(message).unwrap()
session.decrypt(message)?
// TODO save the session
};
// TODO convert the plaintext to a ruma event.
todo!()
let mut json_plaintext = serde_json::from_str::<Value>(&plaintext)?;
let json_object = json_plaintext
.as_object_mut()
.ok_or(OlmError::NotAnObject)?;
json_object.insert("sender".to_owned(), sender.into());
Ok(serde_json::from_value::<EventResult<ToDeviceEvent>>(
json_plaintext,
)?)
}
/// Decrypt a to-device event.
@ -461,16 +467,16 @@ impl OlmMachine {
/// * `event` - The to-device event that should be decrypted.
#[instrument]
async fn decrypt_to_device_event(
&self,
&mut self,
event: &ToDeviceEncrypted,
) -> Result<Option<ToDeviceEvent>> {
) -> Result<EventResult<ToDeviceEvent>> {
info!("Decrypting to-device event");
let content = if let EncryptedEventContent::OlmV1Curve25519AesSha2(c) = &event.content {
c
} else {
warn!("Error, unsupported encryption algorithm");
return Ok(None);
return Err(OlmError::UnsupportedAlgorithm);
};
let identity_keys = self.account.lock().await.identity_keys();
@ -478,13 +484,21 @@ impl OlmMachine {
let own_ciphertext = content.ciphertext.get(own_key);
if let Some(ciphertext) = own_ciphertext {
let message_type: u8 = ciphertext.message_type.try_into().unwrap();
let message_type: u8 = ciphertext
.message_type
.try_into()
.map_err(|_| OlmError::UnsupportedOlmType)?;
let message =
OlmMessage::from_type_and_ciphertext(message_type.into(), ciphertext.body.clone())
.map_err(|_| OlmError::UnsupportedOlmType);
}
.map_err(|_| OlmError::UnsupportedOlmType)?;
todo!()
Ok(self
.decrypt_olm_message(&event.sender.to_string(), &content.sender_key, message)
.await?)
} else {
warn!("Olm event doesn't contain a ciphertext for our key");
Err(OlmError::MissingCiphertext)
}
}
fn handle_room_key_request(&self, _: &ToDeviceRoomKeyRequest) {
@ -496,7 +510,7 @@ impl OlmMachine {
}
#[instrument(skip(response))]
pub fn receive_sync_response(&mut self, response: &mut SyncResponse) {
pub async fn receive_sync_response(&mut self, response: &mut SyncResponse) {
let one_time_key_count = response
.device_one_time_keys_count
.get(&keys::KeyAlgorithm::SignedCurve25519);
@ -519,7 +533,8 @@ impl OlmMachine {
ToDeviceEvent::RoomEncrypted(e) => {
// TODO put the decrypted event into a vec so we can replace
// them in the sync response.
let _ = self.decrypt_to_device_event(e);
let decrypted_event = self.decrypt_to_device_event(e).await;
info!("Decrypted a to-device event {:?}", decrypted_event);
}
ToDeviceEvent::RoomKeyRequest(e) => self.handle_room_key_request(e),
ToDeviceEvent::KeyVerificationAccept(..)

View file

@ -12,9 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
// TODO remove this.
mod error;
#[allow(dead_code)]
// TODO remove this.
mod machine;
#[allow(dead_code)]
mod olm;

View file

@ -24,28 +24,30 @@ use thiserror::Error;
use tokio::sync::Mutex;
use super::olm::{Account, Session};
use olm_rs::errors::OlmAccountError;
use olm_rs::errors::{OlmAccountError, OlmSessionError};
use olm_rs::PicklingMode;
#[cfg(feature = "sqlite-cryptostore")]
pub mod sqlite;
#[cfg(feature = "sqlite-cryptostore")]
use sqlx::Error as SqlxError;
use sqlx::{sqlite::Sqlite, Error as SqlxError};
#[derive(Error, Debug)]
pub enum CryptoStoreError {
#[error("can't read or write from the store")]
Io(#[from] IoError),
#[error("can't finish Olm account operation {0}")]
#[error("can't finish Olm Account operation {0}")]
OlmAccountError(#[from] OlmAccountError),
#[error("can't finish Olm Session operation {0}")]
OlmSessionError(#[from] OlmSessionError),
#[error("URL can't be parsed")]
UrlParse(#[from] ParseError),
// TODO flatten the SqlxError to make it easier for other store
// implementations.
#[cfg(feature = "sqlite-cryptostore")]
#[error("database error")]
DatabaseError(#[from] SqlxError),
DatabaseError(#[from] SqlxError<Sqlite>),
}
pub type Result<T> = std::result::Result<T, CryptoStoreError>;