Skip to content

Commit

Permalink
Trust new identities
Browse files Browse the repository at this point in the history
  • Loading branch information
gferon committed Nov 16, 2023
1 parent f291581 commit 8d77ae1
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 21 deletions.
2 changes: 2 additions & 0 deletions presage-cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ use presage::{
Manager,
};
use presage_store_sled::MigrationConflictStrategy;
use presage_store_sled::OnNewIdentity;
use presage_store_sled::SledStore;
use tempfile::Builder;
use tokio::task;
Expand Down Expand Up @@ -203,6 +204,7 @@ async fn main() -> anyhow::Result<()> {
db_path,
args.passphrase,
MigrationConflictStrategy::Raise,
OnNewIdentity::Trust,
)?;
run(args.subcommand, config_store).await
}
Expand Down
73 changes: 57 additions & 16 deletions presage-store-sled/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ use presage::libsignal_service::{
session_store::SessionStoreExt,
Profile, ServiceAddress,
};
use presage::manager::RegistrationData;
use presage::store::{ContentExt, ContentsStore, PreKeyStoreExt, StateStore, Store, Thread};
use presage::{manager::RegistrationData, proto::verified};
use prost::Message;
use serde::{de::DeserializeOwned, Deserialize, Serialize};
use sha2::{Digest, Sha256};
Expand Down Expand Up @@ -64,6 +64,8 @@ pub struct SledStore {
db: Arc<RwLock<sled::Db>>,
#[cfg(feature = "encryption")]
cipher: Option<Arc<presage_store_cipher::StoreCipher>>,
/// Whether to trust new identities automatically (for instance, when a somebody's phone has changed)
trust_new_identities: OnNewIdentity,
}

/// Sometimes Migrations can't proceed without having to drop existing
Expand Down Expand Up @@ -111,11 +113,18 @@ impl SchemaVersion {
}
}

#[derive(Debug, Clone)]
pub enum OnNewIdentity {
Reject,
Trust,
}

impl SledStore {
#[allow(unused_variables)]
fn new(
db_path: impl AsRef<Path>,
passphrase: Option<impl AsRef<str>>,
trust_new_identities: OnNewIdentity,
) -> Result<Self, SledStoreError> {
let database = sled::open(db_path)?;

Expand All @@ -133,25 +142,33 @@ impl SledStore {
db: Arc::new(RwLock::new(database)),
#[cfg(feature = "encryption")]
cipher: cipher.map(Arc::new),
trust_new_identities,
})
}

pub fn open(
db_path: impl AsRef<Path>,
migration_conflict_strategy: MigrationConflictStrategy,
trust_new_identities: OnNewIdentity,
) -> Result<Self, SledStoreError> {
Self::open_with_passphrase(db_path, None::<&str>, migration_conflict_strategy)
Self::open_with_passphrase(
db_path,
None::<&str>,
migration_conflict_strategy,
trust_new_identities,
)
}

pub fn open_with_passphrase(
db_path: impl AsRef<Path>,
passphrase: Option<impl AsRef<str>>,
migration_conflict_strategy: MigrationConflictStrategy,
trust_new_identities: OnNewIdentity,
) -> Result<Self, SledStoreError> {
let passphrase = passphrase.as_ref();

migrate(&db_path, passphrase, migration_conflict_strategy)?;
Self::new(db_path, passphrase)
Self::new(db_path, passphrase, trust_new_identities)
}

#[cfg(feature = "encryption")]
Expand Down Expand Up @@ -182,6 +199,7 @@ impl SledStore {
#[cfg(feature = "encryption")]
// use store cipher with a random key
cipher: Some(Arc::new(presage_store_cipher::StoreCipher::new())),
trust_new_identities: OnNewIdentity::Reject
})
}

Expand Down Expand Up @@ -297,7 +315,7 @@ fn migrate(
let passphrase = passphrase.as_ref();

let run_migrations = move || {
let mut store = SledStore::new(db_path, passphrase)?;
let mut store = SledStore::new(db_path, passphrase, OnNewIdentity::Reject)?;
let schema_version = store.schema_version();
for step in schema_version.steps() {
match &step {
Expand Down Expand Up @@ -492,7 +510,7 @@ impl ContentsStore for SledStore {
Ok(())
}

fn save_message(&mut self, thread: &Thread, message: Content) -> Result<(), SledStoreError> {
fn save_message(&self, thread: &Thread, message: Content) -> Result<(), SledStoreError> {
let ts = message.timestamp();
log::trace!("storing a message with thread: {thread}, timestamp: {ts}",);

Expand Down Expand Up @@ -968,17 +986,30 @@ impl IdentityKeyStore for SledStore {
identity_key: &IdentityKey,
) -> Result<bool, SignalProtocolError> {
trace!("saving identity");
self.insert(
SLED_TREE_IDENTITIES,
address.to_string(),
identity_key.serialize(),
)
.map_err(|e| {
error!("error saving identity for {:?}: {}", address, e);
e.into_signal_error()
})?;
let existed_before = self
.insert(
SLED_TREE_IDENTITIES,
address.to_string(),
identity_key.serialize(),
)
.map_err(|e| {
error!("error saving identity for {:?}: {}", address, e);
e.into_signal_error()
})?;

if let Ok(uuid) = address.name().parse() {
self.save_trusted_identity_message(
uuid,
*identity_key,
if existed_before {
verified::State::Unverified
} else {
verified::State::Default
},
);
};

Ok(false)
Ok(true)
}

async fn is_trusted_identity(
Expand All @@ -998,7 +1029,17 @@ impl IdentityKeyStore for SledStore {
warn!("trusting new identity {:?}", address);
Ok(true)
}
Some(left_identity_key) => Ok(left_identity_key == *right_identity_key),
// when we encounter some identity we know, we need to decide whether we trust it or not
Some(left_identity_key) => {
if left_identity_key == *right_identity_key {
Ok(true)
} else {
match self.trust_new_identities {
OnNewIdentity::Trust => Ok(true),
OnNewIdentity::Reject => Ok(false),
}
}
}
}
}

Expand Down
48 changes: 43 additions & 5 deletions presage/src/store.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,22 @@
//! Traits that are used by the manager for storing the data.

use std::{fmt, ops::RangeBounds};
use std::{fmt, ops::RangeBounds, time::SystemTime};

use libsignal_service::{
content::ContentBody,
content::{ContentBody, Metadata},
groups_v2::Group,
models::Contact,
prelude::{Content, ProfileKey, Uuid, UuidError},
proto::{
sync_message::{self, Sent},
DataMessage, EditMessage, GroupContextV2, SyncMessage,
verified, DataMessage, EditMessage, GroupContextV2, SyncMessage, Verified,
},
protocol::{ProtocolStore, SenderKeyStore},
protocol::{IdentityKey, ProtocolStore, SenderKeyStore},
session_store::SessionStoreExt,
zkgroup::GroupMasterKeyBytes,
Profile,
};
use log::error;
use serde::{Deserialize, Serialize};

use crate::manager::RegistrationData;
Expand Down Expand Up @@ -87,11 +88,48 @@ pub trait ContentsStore {

/// Save a message in a [Thread] identified by a timestamp.
fn save_message(
&mut self,
&self,
thread: &Thread,
message: Content,
) -> Result<(), Self::ContentsStoreError>;

/// Saves a message to mark an identity as trusted or not
fn save_trusted_identity_message(
&self,
contact: Uuid,
right_identity_key: IdentityKey,
verified_state: verified::State,
) {
// TODO: this is a hack to save a message showing that the verification status changed
// It is possibly ok to do it like this, but rebuidling the metadata and content body feels dirty
let thread = Thread::Contact(contact);
let verified_sync_message = Content {
metadata: Metadata {
sender: contact.into(),
sender_device: 0,
timestamp: SystemTime::now()
.duration_since(SystemTime::UNIX_EPOCH)
.unwrap_or_default()
.as_secs(),
needs_receipt: false,
unidentified_sender: false,
},
body: SyncMessage {
verified: Some(Verified {
destination_aci: Some(contact.to_string()),
identity_key: Some(right_identity_key.public_key().serialize().to_vec()),
state: Some(verified_state.into()),
null_message: None,
}),
..Default::default()
}
.into(),
};
if let Err(error) = self.save_message(&thread, verified_sync_message) {
error!("failed to save the verified session message in thread: {error}");
}
}

/// Delete a single message, identified by its received timestamp from a thread.
/// Useful when you want to delete a message locally only.
fn delete_message(
Expand Down

0 comments on commit 8d77ae1

Please sign in to comment.