crypto: Add a method to manually verify our own user identity

master
Damir Jelić 2021-08-10 13:57:12 +02:00
parent d4fe6f5133
commit 4f46212d1a
4 changed files with 79 additions and 29 deletions

View File

@ -32,11 +32,15 @@ use ruma::{
}; };
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use serde_json::to_value; use serde_json::to_value;
use tracing::error;
use super::{atomic_bool_deserializer, atomic_bool_serializer}; use super::{atomic_bool_deserializer, atomic_bool_serializer};
use crate::{ use crate::{
error::SignatureError, olm::Utility, verification::VerificationMachine, CryptoStoreError, error::SignatureError,
OutgoingVerificationRequest, ReadOnlyDevice, VerificationRequest, olm::Utility,
store::{Changes, IdentityChanges},
verification::VerificationMachine,
CryptoStoreError, OutgoingVerificationRequest, ReadOnlyDevice, VerificationRequest,
}; };
/// Enum over the different user identity types we can have. /// Enum over the different user identity types we can have.
@ -103,6 +107,27 @@ impl Deref for OwnUserIdentity {
} }
impl 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<SignatureUploadRequest, SignatureError> {
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. /// Send a verification request to our other devices.
pub async fn request_verification( pub async fn request_verification(
&self, &self,
@ -680,7 +705,7 @@ impl ReadOnlyUserIdentity {
/// ///
/// Returns a `SignatureError` if the self signing key fails to be correctly /// Returns a `SignatureError` if the self signing key fails to be correctly
/// verified by the given master key. /// verified by the given master key.
pub fn new( pub(crate) fn new(
master_key: MasterPubkey, master_key: MasterPubkey,
self_signing_key: SelfSigningPubkey, self_signing_key: SelfSigningPubkey,
) -> Result<Self, SignatureError> { ) -> Result<Self, SignatureError> {
@ -690,7 +715,7 @@ impl ReadOnlyUserIdentity {
} }
#[cfg(test)] #[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 master_key = identity.master_key.lock().await.as_ref().unwrap().public_key.clone();
let self_signing_key = let self_signing_key =
identity.self_signing_key.lock().await.as_ref().unwrap().public_key.clone(); 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 /// Returns an empty result if the signature check succeeded, otherwise a
/// SignatureError indicating why the check failed. /// 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() { if self.user_id() != device.user_id() {
return Err(SignatureError::UserIdMissmatch); return Err(SignatureError::UserIdMissmatch);
} }
@ -790,7 +815,7 @@ impl ReadOnlyOwnUserIdentity {
/// ///
/// Returns a `SignatureError` if the self signing key fails to be correctly /// Returns a `SignatureError` if the self signing key fails to be correctly
/// verified by the given master key. /// verified by the given master key.
pub fn new( pub(crate) fn new(
master_key: MasterPubkey, master_key: MasterPubkey,
self_signing_key: SelfSigningPubkey, self_signing_key: SelfSigningPubkey,
user_signing_key: UserSigningPubkey, user_signing_key: UserSigningPubkey,
@ -836,7 +861,7 @@ impl ReadOnlyOwnUserIdentity {
/// ///
/// Returns an empty result if the signature check succeeded, otherwise a /// Returns an empty result if the signature check succeeded, otherwise a
/// SignatureError indicating why the check failed. /// SignatureError indicating why the check failed.
pub fn is_identity_signed( pub(crate) fn is_identity_signed(
&self, &self,
identity: &ReadOnlyUserIdentity, identity: &ReadOnlyUserIdentity,
) -> Result<(), SignatureError> { ) -> Result<(), SignatureError> {
@ -855,7 +880,7 @@ impl ReadOnlyOwnUserIdentity {
/// ///
/// Returns an empty result if the signature check succeeded, otherwise a /// Returns an empty result if the signature check succeeded, otherwise a
/// SignatureError indicating why the check failed. /// 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() { if self.user_id() != device.user_id() {
return Err(SignatureError::UserIdMissmatch); return Err(SignatureError::UserIdMissmatch);
} }
@ -886,7 +911,7 @@ impl ReadOnlyOwnUserIdentity {
/// * `user_signing_key` - The new user signing key of user identity. /// * `user_signing_key` - The new user signing key of user identity.
/// ///
/// Returns a `SignatureError` if we failed to update the identity. /// Returns a `SignatureError` if we failed to update the identity.
pub fn update( pub(crate) fn update(
&mut self, &mut self,
master_key: MasterPubkey, master_key: MasterPubkey,
self_signing_key: SelfSigningPubkey, self_signing_key: SelfSigningPubkey,

View File

@ -54,7 +54,7 @@ pub(crate) use olm::ReadOnlyAccount;
pub use olm::{CrossSigningStatus, EncryptionSettings}; pub use olm::{CrossSigningStatus, EncryptionSettings};
pub use requests::{ pub use requests::{
IncomingResponse, KeysQueryRequest, OutgoingRequest, OutgoingRequests, IncomingResponse, KeysQueryRequest, OutgoingRequest, OutgoingRequests,
OutgoingVerificationRequest, RoomMessageRequest, ToDeviceRequest, OutgoingVerificationRequest, RoomMessageRequest, ToDeviceRequest, UploadSigningKeysRequest,
}; };
pub use store::{CrossSigningKeyExport, CryptoStoreError, SecretImportError}; pub use store::{CrossSigningKeyExport, CryptoStoreError, SecretImportError};
pub use verification::{ pub use verification::{

View File

@ -32,7 +32,7 @@ use olm_rs::{
}; };
use ruma::{ use ruma::{
api::client::r0::keys::{upload_keys, upload_signatures::Request as SignatureUploadRequest}, api::client::r0::keys::{upload_keys, upload_signatures::Request as SignatureUploadRequest},
encryption::{DeviceKeys, OneTimeKey, SignedKey}, encryption::{CrossSigningKey, DeviceKeys, OneTimeKey, SignedKey},
events::{ events::{
room::encrypted::{EncryptedEventScheme, EncryptedToDeviceEventContent}, room::encrypted::{EncryptedEventScheme, EncryptedToDeviceEventContent},
AnyToDeviceEvent, ToDeviceEvent, AnyToDeviceEvent, ToDeviceEvent,
@ -52,11 +52,11 @@ use super::{
}; };
use crate::{ use crate::{
error::{EventError, OlmResult, SessionCreationError}, error::{EventError, OlmResult, SessionCreationError},
identities::ReadOnlyDevice, identities::{MasterPubkey, ReadOnlyDevice},
requests::UploadSigningKeysRequest, requests::UploadSigningKeysRequest,
store::{Changes, Store}, store::{Changes, Store},
utilities::encode, utilities::encode,
OlmError, OlmError, SignatureError,
}; };
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -761,6 +761,42 @@ impl ReadOnlyAccount {
PrivateCrossSigningIdentity::new_with_account(self).await 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<SignatureUploadRequest, SignatureError> {
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 /// Convert a JSON value to the canonical representation and sign the JSON
/// string. /// string.
/// ///

View File

@ -28,7 +28,7 @@ use ruma::{
api::client::r0::keys::upload_signatures::Request as SignatureUploadRequest, api::client::r0::keys::upload_signatures::Request as SignatureUploadRequest,
encryption::{DeviceKeys, KeyUsage}, encryption::{DeviceKeys, KeyUsage},
events::secret::request::SecretName, events::secret::request::SecretName,
DeviceKeyAlgorithm, DeviceKeyId, UserId, UserId,
}; };
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use serde_json::Error as JsonError; use serde_json::Error as JsonError;
@ -379,22 +379,11 @@ impl PrivateCrossSigningIdentity {
let mut public_key = let mut public_key =
master.cross_signing_key(account.user_id().to_owned(), KeyUsage::Master); 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 account
.signatures .sign_cross_signing_key(&mut public_key)
.entry(account.user_id().to_owned()) .await
.or_insert_with(BTreeMap::new) .expect("Can't sign our freshly created master key with our account");
.insert(
DeviceKeyId::from_parts(DeviceKeyAlgorithm::Ed25519, account.device_id())
.to_string(),
signature,
);
let master = MasterSigning { inner: master, public_key: public_key.into() }; let master = MasterSigning { inner: master, public_key: public_key.into() };