diff --git a/presage/Cargo.toml b/presage/Cargo.toml index 0fa11ea3d..c677280e6 100644 --- a/presage/Cargo.toml +++ b/presage/Cargo.toml @@ -19,6 +19,7 @@ thiserror = "1.0" url = "2.2" parking_lot = "0.11" tokio = { version = "1.0", default-features = false, features = ["sync", "time"] } +sha2 = "0.10.8" [dev-dependencies] quickcheck = "1.0.3" diff --git a/presage/src/errors.rs b/presage/src/errors.rs index 3b5d1cc38..12d6324e6 100644 --- a/presage/src/errors.rs +++ b/presage/src/errors.rs @@ -8,6 +8,7 @@ use crate::store::StoreError; /// The error type of Signal manager #[derive(thiserror::Error, Debug)] +#[non_exhaustive] pub enum Error { #[error("captcha from https://signalcaptchas.org/registration/generate.html required")] CaptchaRequired, @@ -65,6 +66,8 @@ pub enum Error { PushChallengeRequired, #[error("Not allowed to request verification code, reason unknown: {0:?}")] RequestingCodeForbidden(libsignal_service::push_service::RegistrationSessionMetadataResponse), + #[error("attachment sha256 checksum did not match")] + UnexpectedAttachmentChecksum, #[error("Unverified registration session (i.e. wrong verification code)")] UnverifiedRegistrationSession, } diff --git a/presage/src/manager/registered.rs b/presage/src/manager/registered.rs index 9939789d0..ef5c39cc9 100644 --- a/presage/src/manager/registered.rs +++ b/presage/src/manager/registered.rs @@ -41,6 +41,7 @@ use log::{debug, error, info, trace, warn}; use rand::rngs::StdRng; use rand::SeedableRng; use serde::{Deserialize, Serialize}; +use sha2::Digest; use tokio::sync::Mutex; use crate::cache::CacheCell; @@ -845,15 +846,24 @@ impl Manager { &self, attachment_pointer: &AttachmentPointer, ) -> Result, Error> { + let expected_digest = attachment_pointer + .digest + .as_ref() + .ok_or_else(|| Error::UnexpectedAttachmentChecksum)?; + let mut service = self.identified_push_service(); let mut attachment_stream = service.get_attachment(attachment_pointer).await?; // We need the whole file for the crypto to check out let mut ciphertext = Vec::new(); let len = attachment_stream.read_to_end(&mut ciphertext).await?; - trace!("downloaded encrypted attachment of {} bytes", len); + let digest = sha2::Sha256::digest(&ciphertext); + if &digest[..] != expected_digest { + return Err(Error::UnexpectedAttachmentChecksum); + } + let key: [u8; 64] = attachment_pointer.key().try_into()?; decrypt_in_place(key, &mut ciphertext)?;