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

This commit is contained in:
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_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<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.
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<Self, SignatureError> {
@ -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,

View file

@ -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::{

View file

@ -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<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
/// string.
///

View file

@ -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() };