diff --git a/matrix_sdk_crypto/src/identities/user.rs b/matrix_sdk_crypto/src/identities/user.rs index 6d4f6dcb..839deb25 100644 --- a/matrix_sdk_crypto/src/identities/user.rs +++ b/matrix_sdk_crypto/src/identities/user.rs @@ -32,11 +32,15 @@ use ruma::{ }; use serde::{Deserialize, Serialize}; use serde_json::to_value; +use tracing::error; use super::{atomic_bool_deserializer, atomic_bool_serializer}; use crate::{ - error::SignatureError, olm::Utility, verification::VerificationMachine, CryptoStoreError, - OutgoingVerificationRequest, ReadOnlyDevice, VerificationRequest, + error::SignatureError, + olm::Utility, + store::{Changes, IdentityChanges}, + verification::VerificationMachine, + CryptoStoreError, OutgoingVerificationRequest, ReadOnlyDevice, VerificationRequest, }; /// Enum over the different user identity types we can have. @@ -103,6 +107,27 @@ impl Deref for OwnUserIdentity { } impl OwnUserIdentity { + /// Mark our user identity as verified. + /// + /// This will mark the identity locally as verified and sign it with our own + /// device. + /// + /// Returns a signature upload request that needs to be sent out. + pub async fn verify(&self) -> Result { + self.mark_as_verified(); + + let changes = Changes { + identities: IdentityChanges { changed: vec![self.inner.clone().into()], new: vec![] }, + ..Default::default() + }; + + if let Err(e) = self.verification_machine.store.save_changes(changes).await { + error!(error =? e, "Couldn't store our own user identity after marking it as verified"); + } + + self.verification_machine.store.account.sign_master_key(self.master_key.clone()).await + } + /// Send a verification request to our other devices. pub async fn request_verification( &self, @@ -680,7 +705,7 @@ impl ReadOnlyUserIdentity { /// /// Returns a `SignatureError` if the self signing key fails to be correctly /// verified by the given master key. - pub fn new( + pub(crate) fn new( master_key: MasterPubkey, self_signing_key: SelfSigningPubkey, ) -> Result { @@ -690,7 +715,7 @@ impl ReadOnlyUserIdentity { } #[cfg(test)] - pub async fn from_private(identity: &crate::olm::PrivateCrossSigningIdentity) -> Self { + pub(crate) async fn from_private(identity: &crate::olm::PrivateCrossSigningIdentity) -> Self { let master_key = identity.master_key.lock().await.as_ref().unwrap().public_key.clone(); let self_signing_key = identity.self_signing_key.lock().await.as_ref().unwrap().public_key.clone(); @@ -747,7 +772,7 @@ impl ReadOnlyUserIdentity { /// /// Returns an empty result if the signature check succeeded, otherwise a /// SignatureError indicating why the check failed. - pub fn is_device_signed(&self, device: &ReadOnlyDevice) -> Result<(), SignatureError> { + pub(crate) fn is_device_signed(&self, device: &ReadOnlyDevice) -> Result<(), SignatureError> { if self.user_id() != device.user_id() { return Err(SignatureError::UserIdMissmatch); } @@ -790,7 +815,7 @@ impl ReadOnlyOwnUserIdentity { /// /// Returns a `SignatureError` if the self signing key fails to be correctly /// verified by the given master key. - pub fn new( + pub(crate) fn new( master_key: MasterPubkey, self_signing_key: SelfSigningPubkey, user_signing_key: UserSigningPubkey, @@ -836,7 +861,7 @@ impl ReadOnlyOwnUserIdentity { /// /// Returns an empty result if the signature check succeeded, otherwise a /// SignatureError indicating why the check failed. - pub fn is_identity_signed( + pub(crate) fn is_identity_signed( &self, identity: &ReadOnlyUserIdentity, ) -> Result<(), SignatureError> { @@ -855,7 +880,7 @@ impl ReadOnlyOwnUserIdentity { /// /// Returns an empty result if the signature check succeeded, otherwise a /// SignatureError indicating why the check failed. - pub fn is_device_signed(&self, device: &ReadOnlyDevice) -> Result<(), SignatureError> { + pub(crate) fn is_device_signed(&self, device: &ReadOnlyDevice) -> Result<(), SignatureError> { if self.user_id() != device.user_id() { return Err(SignatureError::UserIdMissmatch); } @@ -886,7 +911,7 @@ impl ReadOnlyOwnUserIdentity { /// * `user_signing_key` - The new user signing key of user identity. /// /// Returns a `SignatureError` if we failed to update the identity. - pub fn update( + pub(crate) fn update( &mut self, master_key: MasterPubkey, self_signing_key: SelfSigningPubkey, diff --git a/matrix_sdk_crypto/src/lib.rs b/matrix_sdk_crypto/src/lib.rs index 8a9c5901..7169b56c 100644 --- a/matrix_sdk_crypto/src/lib.rs +++ b/matrix_sdk_crypto/src/lib.rs @@ -54,7 +54,7 @@ pub(crate) use olm::ReadOnlyAccount; pub use olm::{CrossSigningStatus, EncryptionSettings}; pub use requests::{ IncomingResponse, KeysQueryRequest, OutgoingRequest, OutgoingRequests, - OutgoingVerificationRequest, RoomMessageRequest, ToDeviceRequest, + OutgoingVerificationRequest, RoomMessageRequest, ToDeviceRequest, UploadSigningKeysRequest, }; pub use store::{CrossSigningKeyExport, CryptoStoreError, SecretImportError}; pub use verification::{ diff --git a/matrix_sdk_crypto/src/olm/account.rs b/matrix_sdk_crypto/src/olm/account.rs index bd47447e..fc990e29 100644 --- a/matrix_sdk_crypto/src/olm/account.rs +++ b/matrix_sdk_crypto/src/olm/account.rs @@ -32,7 +32,7 @@ use olm_rs::{ }; use ruma::{ api::client::r0::keys::{upload_keys, upload_signatures::Request as SignatureUploadRequest}, - encryption::{DeviceKeys, OneTimeKey, SignedKey}, + encryption::{CrossSigningKey, DeviceKeys, OneTimeKey, SignedKey}, events::{ room::encrypted::{EncryptedEventScheme, EncryptedToDeviceEventContent}, AnyToDeviceEvent, ToDeviceEvent, @@ -52,11 +52,11 @@ use super::{ }; use crate::{ error::{EventError, OlmResult, SessionCreationError}, - identities::ReadOnlyDevice, + identities::{MasterPubkey, ReadOnlyDevice}, requests::UploadSigningKeysRequest, store::{Changes, Store}, utilities::encode, - OlmError, + OlmError, SignatureError, }; #[derive(Debug, Clone)] @@ -761,6 +761,42 @@ impl ReadOnlyAccount { PrivateCrossSigningIdentity::new_with_account(self).await } + pub(crate) async fn sign_cross_signing_key( + &self, + cross_signing_key: &mut CrossSigningKey, + ) -> Result<(), SignatureError> { + let signature = self.sign_json(serde_json::to_value(&cross_signing_key)?).await; + + cross_signing_key + .signatures + .entry(self.user_id().to_owned()) + .or_insert_with(BTreeMap::new) + .insert( + DeviceKeyId::from_parts(DeviceKeyAlgorithm::Ed25519, self.device_id()).to_string(), + signature, + ); + + Ok(()) + } + + pub(crate) async fn sign_master_key( + &self, + master_key: MasterPubkey, + ) -> Result { + let public_key = + master_key.get_first_key().ok_or(SignatureError::MissingSigningKey)?.to_string(); + let mut cross_signing_key = master_key.into(); + self.sign_cross_signing_key(&mut cross_signing_key).await?; + + let mut signed_keys = BTreeMap::new(); + signed_keys + .entry(self.user_id().to_owned()) + .or_insert_with(BTreeMap::new) + .insert(public_key, serde_json::to_value(cross_signing_key)?); + + Ok(SignatureUploadRequest::new(signed_keys)) + } + /// Convert a JSON value to the canonical representation and sign the JSON /// string. /// diff --git a/matrix_sdk_crypto/src/olm/signing/mod.rs b/matrix_sdk_crypto/src/olm/signing/mod.rs index 77ae6b25..bb67c4cc 100644 --- a/matrix_sdk_crypto/src/olm/signing/mod.rs +++ b/matrix_sdk_crypto/src/olm/signing/mod.rs @@ -28,7 +28,7 @@ use ruma::{ api::client::r0::keys::upload_signatures::Request as SignatureUploadRequest, encryption::{DeviceKeys, KeyUsage}, events::secret::request::SecretName, - DeviceKeyAlgorithm, DeviceKeyId, UserId, + UserId, }; use serde::{Deserialize, Serialize}; use serde_json::Error as JsonError; @@ -379,22 +379,11 @@ impl PrivateCrossSigningIdentity { let mut public_key = master.cross_signing_key(account.user_id().to_owned(), KeyUsage::Master); - let signature = account - .sign_json( - serde_json::to_value(&public_key) - .expect("Can't convert own public master key to json"), - ) - .await; - public_key - .signatures - .entry(account.user_id().to_owned()) - .or_insert_with(BTreeMap::new) - .insert( - DeviceKeyId::from_parts(DeviceKeyAlgorithm::Ed25519, account.device_id()) - .to_string(), - signature, - ); + account + .sign_cross_signing_key(&mut public_key) + .await + .expect("Can't sign our freshly created master key with our account"); let master = MasterSigning { inner: master, public_key: public_key.into() };