crypto: Add a method to manually verify our own user identity
This commit is contained in:
parent
d4fe6f5133
commit
4f46212d1a
4 changed files with 79 additions and 29 deletions
|
@ -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,
|
||||||
|
|
|
@ -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::{
|
||||||
|
|
|
@ -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.
|
||||||
///
|
///
|
||||||
|
|
|
@ -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() };
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue