matrix_sdk/encryption/identities/devices.rs
1// Copyright 2021 The Matrix.org Foundation C.I.C.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use std::{collections::BTreeMap, ops::Deref};
16
17use matrix_sdk_base::crypto::{
18 store::CryptoStoreError, Device as BaseDevice, DeviceData, LocalTrust,
19 UserDevices as BaseUserDevices,
20};
21use ruma::{events::key::verification::VerificationMethod, DeviceId, OwnedDeviceId, OwnedUserId};
22
23use super::ManualVerifyError;
24use crate::{
25 encryption::verification::{SasVerification, VerificationRequest},
26 error::Result,
27 Client,
28};
29
30/// Updates about [`Device`]s which got received over the `/keys/query`
31/// endpoint.
32#[derive(Clone, Debug, Default)]
33pub struct DeviceUpdates {
34 /// The list of newly discovered devices.
35 ///
36 /// A device being in this list does not necessarily mean that the device
37 /// was just created, it just means that it's the first time we're
38 /// seeing this device.
39 pub new: BTreeMap<OwnedUserId, BTreeMap<OwnedDeviceId, Device>>,
40 /// The list of changed devices.
41 pub changed: BTreeMap<OwnedUserId, BTreeMap<OwnedDeviceId, Device>>,
42}
43
44impl DeviceUpdates {
45 pub(crate) fn new(
46 client: Client,
47 updates: matrix_sdk_base::crypto::store::DeviceUpdates,
48 ) -> Self {
49 let map_devices = |(user_id, devices)| {
50 // For some reason we need to tell Rust the type of `devices`.
51 let devices: BTreeMap<_, _> = devices;
52
53 (
54 user_id,
55 devices
56 .into_iter()
57 .map(|(device_id, device)| {
58 (device_id, Device { inner: device, client: client.to_owned() })
59 })
60 .collect(),
61 )
62 };
63
64 let new = updates.new.into_iter().map(map_devices).collect();
65 let changed = updates.changed.into_iter().map(map_devices).collect();
66
67 DeviceUpdates { new, changed }
68 }
69}
70
71/// A device represents a E2EE capable client or device of an user.
72///
73/// A `Device` is backed by [device keys] that are uploaded to the server.
74///
75/// The [device keys] for our own device will be automatically uploaded by the
76/// SDK and the private parts of our device keys never leave this device.
77///
78/// Device keys consist of an Ed25519 keypair and a Curve25519 keypair. Only the
79/// public parts of those keypairs will be uploaded to the server.
80///
81/// ```text
82/// ┌──────────────────────────────────┐
83/// │ Device │
84/// ├──────────────────────────────────┤
85/// │ Device Keys │
86/// ├────────────────┬─────────────────┤
87/// │ Ed25519 Key │ Curve25519 Key │
88/// └────────────────┴─────────────────┘
89/// ```
90///
91/// The Ed25519 key will be used to uniquely identify the `Device` while the
92/// Curve25519 key is used to establish 1-to-1 encrypted communication channels
93/// between two devices.
94///
95/// [device keys]: https://spec.matrix.org/unstable/client-server-api/#device-keys
96#[derive(Clone, Debug)]
97pub struct Device {
98 pub(crate) inner: BaseDevice,
99 pub(crate) client: Client,
100}
101
102impl Deref for Device {
103 type Target = DeviceData;
104
105 fn deref(&self) -> &Self::Target {
106 &self.inner
107 }
108}
109
110impl Device {
111 /// Request an interactive verification with this `Device`.
112 ///
113 /// Returns a [`VerificationRequest`] object that can be used to control the
114 /// verification flow.
115 ///
116 /// The default methods that are supported are `m.sas.v1` and
117 /// `m.qr_code.show.v1`, if this isn't desirable the
118 /// [`request_verification_with_methods()`] method can be used to override
119 /// this. `m.qr_code.show.v1` is only available if the `qrcode` feature is
120 /// enabled, which it is by default.
121 ///
122 /// # Examples
123 ///
124 /// ```no_run
125 /// # use matrix_sdk::{Client, ruma::{device_id, user_id}};
126 /// # use url::Url;
127 /// # async {
128 /// # let alice = user_id!("@alice:example.org");
129 /// # let homeserver = Url::parse("http://example.com")?;
130 /// # let client = Client::new(homeserver).await?;
131 /// let device =
132 /// client.encryption().get_device(alice, device_id!("DEVICEID")).await?;
133 ///
134 /// if let Some(device) = device {
135 /// let verification = device.request_verification().await?;
136 /// }
137 /// # anyhow::Ok(()) };
138 /// ```
139 ///
140 /// [`request_verification_with_methods()`]:
141 /// #method.request_verification_with_methods
142 pub async fn request_verification(&self) -> Result<VerificationRequest> {
143 let (verification, request) = self.inner.request_verification();
144 self.client.send_verification_request(request).await?;
145
146 Ok(VerificationRequest { inner: verification, client: self.client.clone() })
147 }
148
149 /// Request an interactive verification with this `Device`.
150 ///
151 /// Returns a [`VerificationRequest`] object that can be used to control the
152 /// verification flow.
153 ///
154 /// # Arguments
155 ///
156 /// * `methods` - The verification methods that we want to support. Must be
157 /// non-empty.
158 ///
159 /// # Panics
160 ///
161 /// This method will panic if `methods` is empty.
162 ///
163 /// # Examples
164 ///
165 /// ```no_run
166 /// # use matrix_sdk::{
167 /// # Client,
168 /// # ruma::{
169 /// # device_id, user_id,
170 /// # events::key::verification::VerificationMethod,
171 /// # }
172 /// # };
173 /// # use url::Url;
174 /// # async {
175 /// # let alice = user_id!("@alice:example.org");
176 /// # let homeserver = Url::parse("http://example.com")?;
177 /// # let client = Client::new(homeserver).await?;
178 /// let device =
179 /// client.encryption().get_device(alice, device_id!("DEVICEID")).await?;
180 ///
181 /// // We don't want to support showing a QR code, we only support SAS
182 /// // verification
183 /// let methods = vec![VerificationMethod::SasV1];
184 ///
185 /// if let Some(device) = device {
186 /// let verification =
187 /// device.request_verification_with_methods(methods).await?;
188 /// }
189 /// # anyhow::Ok(()) };
190 /// ```
191 pub async fn request_verification_with_methods(
192 &self,
193 methods: Vec<VerificationMethod>,
194 ) -> Result<VerificationRequest> {
195 assert!(!methods.is_empty(), "The list of verification methods can't be non-empty");
196
197 let (verification, request) = self.inner.request_verification_with_methods(methods);
198 self.client.send_verification_request(request).await?;
199
200 Ok(VerificationRequest { inner: verification, client: self.client.clone() })
201 }
202
203 /// Start an interactive verification with this [`Device`]
204 ///
205 /// Returns a [`SasVerification`] object that represents the interactive
206 /// verification flow.
207 ///
208 /// This method has been deprecated in the spec and the
209 /// [`request_verification()`] method should be used instead.
210 ///
211 /// # Examples
212 ///
213 /// ```no_run
214 /// # use matrix_sdk::{Client, ruma::{device_id, user_id}};
215 /// # use url::Url;
216 /// # async {
217 /// # let alice = user_id!("@alice:example.org");
218 /// # let homeserver = Url::parse("http://example.com")?;
219 /// # let client = Client::new(homeserver).await?;
220 /// let device =
221 /// client.encryption().get_device(alice, device_id!("DEVICEID")).await?;
222 ///
223 /// if let Some(device) = device {
224 /// let verification = device.start_verification().await?;
225 /// }
226 /// # anyhow::Ok(()) };
227 /// ```
228 ///
229 /// [`request_verification()`]: #method.request_verification
230 #[deprecated(
231 since = "0.4.0",
232 note = "directly starting a verification is deprecated in the spec. \
233 Users should instead use request_verification()"
234 )]
235 pub async fn start_verification(&self) -> Result<SasVerification> {
236 let (sas, request) = self.inner.start_verification().await?;
237 self.client.send_to_device(&request).await?;
238
239 Ok(SasVerification { inner: sas, client: self.client.clone() })
240 }
241
242 /// Manually verify this device.
243 ///
244 /// This method will attempt to sign the device using our private cross
245 /// signing key.
246 ///
247 /// This method will always fail if the device belongs to someone else, we
248 /// can only sign our own devices.
249 ///
250 /// It can also fail if we don't have the private part of our self-signing
251 /// key.
252 ///
253 /// The state of our private cross signing keys can be inspected using the
254 /// [`Encryption::cross_signing_status()`] method.
255 ///
256 /// [`Encryption::cross_signing_status()`]: crate::encryption::Encryption::cross_signing_status
257 ///
258 /// ### Problems of manual verification
259 ///
260 /// Manual verification may be more convenient to use, i.e. both devices
261 /// need to be online and available to interactively verify each other.
262 /// Despite the convenience, interactive verifications should be
263 /// generally preferred. Manually verifying a device won't notify the
264 /// other device, the one being verified, that they should also verify
265 /// us. This means that device `A` will consider device `B` to be
266 /// verified, but not the other way around.
267 ///
268 /// # Examples
269 ///
270 /// ```no_run
271 /// # use matrix_sdk::{
272 /// # Client,
273 /// # ruma::{
274 /// # device_id, user_id,
275 /// # events::key::verification::VerificationMethod,
276 /// # }
277 /// # };
278 /// # use url::Url;
279 /// # async {
280 /// # let alice = user_id!("@alice:example.org");
281 /// # let homeserver = Url::parse("http://example.com")?;
282 /// # let client = Client::new(homeserver).await?;
283 /// let device =
284 /// client.encryption().get_device(alice, device_id!("DEVICEID")).await?;
285 ///
286 /// if let Some(device) = device {
287 /// device.verify().await?;
288 /// }
289 /// # anyhow::Ok(()) };
290 /// ```
291 pub async fn verify(&self) -> Result<(), ManualVerifyError> {
292 let request = self.inner.verify().await?;
293 self.client.send(request).await?;
294
295 Ok(())
296 }
297
298 /// Is the device considered to be verified.
299 ///
300 /// A device is considered to be verified, either if it's locally marked as
301 /// such, or if it's signed by the appropriate cross signing key. Our own
302 /// device, is always implicitly verified.
303 ///
304 /// ## Local trust
305 ///
306 /// Local trust can be established using the [`Device::set_local_trust()`]
307 /// method or it will be established if we interactively verify the device
308 /// using [`Device::request_verification()`].
309 ///
310 /// **Note**: The concept of local trust is largely deprecated because it
311 /// can't be shared with other devices. Every device needs to verify all the
312 /// other devices it communicates to. Because this becomes quickly
313 /// unsustainable verification has migrated to cross signing verification.
314 ///
315 /// ## Cross signing verification
316 ///
317 /// Cross signing verification uses signatures over devices and user
318 /// identities to check if a device is considered to be verified. The
319 /// signatures can be uploaded to the homeserver, this allows us to
320 /// share the verification state with other devices. Devices only need to
321 /// verify a user identity, if the user identity has verified and signed
322 /// the device we can consider the device to be verified as well.
323 ///
324 /// Devices are usually cross signing verified using interactive
325 /// verification, which can be started using the
326 /// [`Device::request_verification()`] method.
327 ///
328 /// A [`Device`] can also be manually signed using the [`Device::verify()`]
329 /// method, this works only for devices belonging to our own user.
330 ///
331 /// Do note that the device that is being manually signed will not trust our
332 /// own user identity like it would if we interactively verify the device.
333 /// Such a device can mark our own user as verified using the
334 /// [`UserIdentity::verify()`] method.
335 ///
336 /// ### Verification of devices belonging to our own user.
337 ///
338 /// If the device belongs to our own user, the device will be considered to
339 /// be verified if:
340 ///
341 /// * The device has been signed by our self-signing key
342 /// * Our own user identity is considered to be [verified]
343 ///
344 /// In other words we need to find a valid signature chain from our user
345 /// identity to the device:
346 ///
347 ///```text
348 /// ┌─────────────────────────────────────┐ ┌─────────────┐
349 /// │ Own User Identity │ │ Device │
350 /// ├──────────────────┬──────────────────┤───►├─────────────┤
351 /// │ Master Key │ Self-signing Key │ │ Device Keys │
352 /// └──────────────────┴──────────────────┘ └─────────────┘
353 /// ```
354 ///
355 /// ### Verification of devices belonging to other users.
356 ///
357 /// If the device belongs to some other user it will be considered to be
358 /// verified if:
359 ///
360 /// * The device has been signed by the user's self-signing key
361 /// * The user's master-signing key has been signed by our own user-signing
362 /// key, i.e. our own identity trusts the other users identity.
363 /// * Our own user identity is considered to be [verified]
364 ///
365 /// ```text
366 /// ┌─────────────────────────────────────┐
367 /// │ Own User Identity │
368 /// ├──────────────────┬──────────────────┤─────┐
369 /// │ Master Key │ User-signing Key │ │
370 /// └──────────────────┴──────────────────┘ │
371 /// ┌───────────────────────────────────────────────────┘
372 /// │
373 /// │ ┌─────────────────────────────────────┐ ┌─────────────┐
374 /// │ │ User Identity │ │ Device │
375 /// └──────►├──────────────────┬──────────────────┤───►│─────────────│
376 /// │ Master Key │ Self-signing Key │ │ Device Keys │
377 /// └──────────────────┴──────────────────┘ └─────────────┘
378 /// ```
379 ///
380 /// # Examples
381 ///
382 /// Let's check if a device is verified:
383 ///
384 /// ```no_run
385 /// # use matrix_sdk::{
386 /// # Client,
387 /// # ruma::{
388 /// # device_id, user_id,
389 /// # events::key::verification::VerificationMethod,
390 /// # }
391 /// # };
392 /// # use url::Url;
393 /// # async {
394 /// # let alice = user_id!("@alice:example.org");
395 /// # let homeserver = Url::parse("http://example.com")?;
396 /// # let client = Client::new(homeserver).await?;
397 /// let device =
398 /// client.encryption().get_device(alice, device_id!("DEVICEID")).await?;
399 ///
400 /// if let Some(device) = device {
401 /// if device.is_verified() {
402 /// println!(
403 /// "Device {} of user {} is verified",
404 /// device.device_id(),
405 /// device.user_id(),
406 /// );
407 /// } else {
408 /// println!(
409 /// "Device {} of user {} is not verified",
410 /// device.device_id(),
411 /// device.user_id(),
412 /// );
413 /// }
414 /// }
415 /// # anyhow::Ok(()) };
416 /// ```
417 ///
418 /// [`UserIdentity::verify()`]:
419 /// crate::encryption::identities::UserIdentity::verify
420 /// [verified]: crate::encryption::identities::UserIdentity::is_verified
421 pub fn is_verified(&self) -> bool {
422 self.inner.is_verified()
423 }
424
425 /// Is the device considered to be verified with cross-signing.
426 ///
427 /// A device is considered to be verified if it's signed by the appropriate
428 /// cross-signing key.
429 ///
430 /// ## Cross-signing verification
431 ///
432 /// Cross-signing verification uses signatures over devices and user
433 /// identities to check if a device is considered to be verified. The
434 /// signatures can be uploaded to the homeserver, this allows us to
435 /// share the verification state with other devices. Devices only need to
436 /// verify a user identity, if the user identity has verified and signed
437 /// the device we can consider the device to be verified as well.
438 ///
439 /// Devices are usually cross-signing verified using interactive
440 /// verification, which can be started using the
441 /// [`Device::request_verification()`] method.
442 ///
443 /// A [`Device`] can also be manually signed using the [`Device::verify()`]
444 /// method, this works only for devices belonging to our own user.
445 ///
446 /// Do note that the device that is being manually signed will not trust our
447 /// own user identity like it would if we interactively verify the device.
448 /// Such a device can mark our own user as verified using the
449 /// [`UserIdentity::verify()`] method.
450 ///
451 /// ### Verification of devices belonging to our own user.
452 ///
453 /// If the device belongs to our own user, the device will be considered to
454 /// be verified if:
455 ///
456 /// * The device has been signed by our self-signing key
457 /// * Our own user identity is considered to be [verified]
458 ///
459 /// In other words we need to find a valid signature chain from our user
460 /// identity to the device:
461 ///
462 ///```text
463 /// ┌─────────────────────────────────────┐ ┌─────────────┐
464 /// │ Own User Identity │ │ Device │
465 /// ├──────────────────┬──────────────────┤───►├─────────────┤
466 /// │ Master Key │ Self-signing Key │ │ Device Keys │
467 /// └──────────────────┴──────────────────┘ └─────────────┘
468 /// ```
469 ///
470 /// ### Verification of devices belonging to other users.
471 ///
472 /// If the device belongs to some other user it will be considered to be
473 /// verified if:
474 ///
475 /// * The device has been signed by the user's self-signing key
476 /// * The user's master-signing key has been signed by our own user-signing
477 /// key, i.e. our own identity trusts the other users identity.
478 /// * Our own user identity is considered to be [verified]
479 ///
480 /// ```text
481 /// ┌─────────────────────────────────────┐
482 /// │ Own User Identity │
483 /// ├──────────────────┬──────────────────┤─────┐
484 /// │ Master Key │ User-signing Key │ │
485 /// └──────────────────┴──────────────────┘ │
486 /// ┌───────────────────────────────────────────────────┘
487 /// │
488 /// │ ┌─────────────────────────────────────┐ ┌─────────────┐
489 /// │ │ User Identity │ │ Device │
490 /// └──────►├──────────────────┬──────────────────┤───►│─────────────│
491 /// │ Master Key │ Self-signing Key │ │ Device Keys │
492 /// └──────────────────┴──────────────────┘ └─────────────┘
493 /// ```
494 ///
495 /// # Examples
496 ///
497 /// Let's check if a device is verified:
498 ///
499 /// ```no_run
500 /// # use matrix_sdk::{
501 /// # Client,
502 /// # ruma::{
503 /// # device_id, user_id,
504 /// # events::key::verification::VerificationMethod,
505 /// # }
506 /// # };
507 /// # use url::Url;
508 /// # async {
509 /// # let alice = user_id!("@alice:example.org");
510 /// # let homeserver = Url::parse("http://example.com")?;
511 /// # let client = Client::new(homeserver).await?;
512 /// let device =
513 /// client.encryption().get_device(alice, device_id!("DEVICEID")).await?;
514 ///
515 /// if let Some(device) = device {
516 /// if device.is_verified_with_cross_signing() {
517 /// println!(
518 /// "Device {} of user {} is verified with cross-signing",
519 /// device.device_id(),
520 /// device.user_id()
521 /// );
522 /// } else {
523 /// println!(
524 /// "Device {} of user {} is not verified with cross-signing",
525 /// device.device_id(),
526 /// device.user_id()
527 /// );
528 /// }
529 /// }
530 /// # anyhow::Ok(()) };
531 /// ```
532 ///
533 /// [`UserIdentity::verify()`]:
534 /// crate::encryption::identities::UserIdentity::verify
535 /// [verified]: crate::encryption::identities::UserIdentity::is_verified
536 pub fn is_verified_with_cross_signing(&self) -> bool {
537 self.inner.is_cross_signing_trusted()
538 }
539
540 /// Set the local trust state of the device to the given state.
541 ///
542 /// This won't affect any cross signing verification state, this only sets
543 /// a flag marking to have the given trust state.
544 ///
545 /// # Arguments
546 ///
547 /// * `trust_state` - The new trust state that should be set for the device.
548 pub async fn set_local_trust(&self, trust_state: LocalTrust) -> Result<(), CryptoStoreError> {
549 self.inner.set_local_trust(trust_state).await
550 }
551
552 /// Is the device cross-signed by its own user.
553 pub fn is_cross_signed_by_owner(&self) -> bool {
554 self.inner.is_cross_signed_by_owner()
555 }
556}
557
558/// The collection of all the [`Device`]s a user has.
559#[derive(Debug)]
560pub struct UserDevices {
561 pub(crate) inner: BaseUserDevices,
562 pub(crate) client: Client,
563}
564
565impl UserDevices {
566 /// Get the specific device with the given device ID.
567 pub fn get(&self, device_id: &DeviceId) -> Option<Device> {
568 self.inner.get(device_id).map(|d| Device { inner: d, client: self.client.clone() })
569 }
570
571 /// Iterator over all the device ids of the user devices.
572 pub fn keys(&self) -> impl Iterator<Item = &DeviceId> {
573 self.inner.keys()
574 }
575
576 /// Iterator over all the devices of the user devices.
577 pub fn devices(&self) -> impl Iterator<Item = Device> + '_ {
578 let client = self.client.clone();
579
580 self.inner.devices().map(move |d| Device { inner: d, client: client.clone() })
581 }
582}