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 Device as BaseDevice, DeviceData, LocalTrust, UserDevices as BaseUserDevices,
19 store::CryptoStoreError,
20};
21use ruma::{DeviceId, OwnedDeviceId, OwnedUserId, events::key::verification::VerificationMethod};
22
23use super::ManualVerifyError;
24use crate::{
25 Client,
26 encryption::verification::{SasVerification, VerificationRequest},
27 error::Result,
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 seeing
38 /// 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::types::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()`]: #method.request_verification_with_methods
141 pub async fn request_verification(&self) -> Result<VerificationRequest> {
142 let (verification, request) = self.inner.request_verification();
143 self.client.send_verification_request(request).await?;
144
145 Ok(VerificationRequest { inner: verification, client: self.client.clone() })
146 }
147
148 /// Request an interactive verification with this `Device`.
149 ///
150 /// Returns a [`VerificationRequest`] object that can be used to control the
151 /// verification flow.
152 ///
153 /// # Arguments
154 ///
155 /// - `methods` - The verification methods that we want to support. Must be
156 /// non-empty.
157 ///
158 /// # Panics
159 ///
160 /// This method will panic if `methods` is empty.
161 ///
162 /// # Examples
163 ///
164 /// ```no_run
165 /// # use matrix_sdk::{
166 /// # Client,
167 /// # ruma::{
168 /// # device_id, user_id,
169 /// # events::key::verification::VerificationMethod,
170 /// # }
171 /// # };
172 /// # use url::Url;
173 /// # async {
174 /// # let alice = user_id!("@alice:example.org");
175 /// # let homeserver = Url::parse("http://example.com")?;
176 /// # let client = Client::new(homeserver).await?;
177 /// let device =
178 /// client.encryption().get_device(alice, device_id!("DEVICEID")).await?;
179 ///
180 /// // We don't want to support showing a QR code, we only support SAS
181 /// // verification
182 /// let methods = vec![VerificationMethod::SasV1];
183 ///
184 /// if let Some(device) = device {
185 /// let verification =
186 /// device.request_verification_with_methods(methods).await?;
187 /// }
188 /// # anyhow::Ok(()) };
189 /// ```
190 pub async fn request_verification_with_methods(
191 &self,
192 methods: Vec<VerificationMethod>,
193 ) -> Result<VerificationRequest> {
194 assert!(!methods.is_empty(), "The list of verification methods can't be non-empty");
195
196 let (verification, request) = self.inner.request_verification_with_methods(methods);
197 self.client.send_verification_request(request).await?;
198
199 Ok(VerificationRequest { inner: verification, client: self.client.clone() })
200 }
201
202 /// Start an interactive verification with this [`Device`]
203 ///
204 /// Returns a [`SasVerification`] object that represents the interactive
205 /// verification flow.
206 ///
207 /// This method has been deprecated in the spec and the
208 /// [`request_verification()`] method should be used instead.
209 ///
210 /// # Examples
211 ///
212 /// ```no_run
213 /// # use matrix_sdk::{Client, ruma::{device_id, user_id}};
214 /// # use url::Url;
215 /// # async {
216 /// # let alice = user_id!("@alice:example.org");
217 /// # let homeserver = Url::parse("http://example.com")?;
218 /// # let client = Client::new(homeserver).await?;
219 /// let device =
220 /// client.encryption().get_device(alice, device_id!("DEVICEID")).await?;
221 ///
222 /// if let Some(device) = device {
223 /// let verification = device.start_verification().await?;
224 /// }
225 /// # anyhow::Ok(()) };
226 /// ```
227 ///
228 /// [`request_verification()`]: #method.request_verification
229 #[deprecated(
230 since = "0.4.0",
231 note = "directly starting a verification is deprecated in the spec. \
232 Users should instead use request_verification()"
233 )]
234 pub async fn start_verification(&self) -> Result<SasVerification> {
235 let (sas, request) = self.inner.start_verification().await?;
236 self.client.send_to_device(&request).await?;
237
238 Ok(SasVerification { inner: Box::new(sas), client: self.client.clone() })
239 }
240
241 /// Manually verify this device.
242 ///
243 /// This method will attempt to sign the device using our private cross
244 /// signing key.
245 ///
246 /// This method will always fail if the device belongs to someone else, we
247 /// can only sign our own devices.
248 ///
249 /// It can also fail if we don't have the private part of our self-signing
250 /// key.
251 ///
252 /// The state of our private cross signing keys can be inspected using the
253 /// [`Encryption::cross_signing_status()`] method.
254 ///
255 /// [`Encryption::cross_signing_status()`]: crate::encryption::Encryption::cross_signing_status
256 ///
257 /// ### Problems of manual verification
258 ///
259 /// Manual verification may be more convenient to use, i.e. both devices
260 /// need to be online and available to interactively verify each other.
261 /// Despite the convenience, interactive verifications should be generally
262 /// preferred. Manually verifying a device won't notify the other device,
263 /// the one being verified, that they should also verify us. This means that
264 /// device `A` will consider device `B` to be verified, but not the other
265 /// way around.
266 ///
267 /// # Examples
268 ///
269 /// ```no_run
270 /// # use matrix_sdk::{
271 /// # Client,
272 /// # ruma::{
273 /// # device_id, user_id,
274 /// # events::key::verification::VerificationMethod,
275 /// # }
276 /// # };
277 /// # use url::Url;
278 /// # async {
279 /// # let alice = user_id!("@alice:example.org");
280 /// # let homeserver = Url::parse("http://example.com")?;
281 /// # let client = Client::new(homeserver).await?;
282 /// let device =
283 /// client.encryption().get_device(alice, device_id!("DEVICEID")).await?;
284 ///
285 /// if let Some(device) = device {
286 /// device.verify().await?;
287 /// }
288 /// # anyhow::Ok(()) };
289 /// ```
290 pub async fn verify(&self) -> Result<(), ManualVerifyError> {
291 let request = self.inner.verify().await?;
292 self.client.send(request).await?;
293
294 Ok(())
295 }
296
297 /// Is the device considered to be verified.
298 ///
299 /// A device is considered to be verified, either if it's locally marked as
300 /// such, or if it's signed by the appropriate cross signing key. Our own
301 /// device, is always implicitly verified.
302 ///
303 /// ## Local trust
304 ///
305 /// Local trust can be established using the [`Device::set_local_trust()`]
306 /// method or it will be established if we interactively verify the device
307 /// using [`Device::request_verification()`].
308 ///
309 /// **Note**: The concept of local trust is largely deprecated because it
310 /// can't be shared with other devices. Every device needs to verify all the
311 /// other devices it communicates to. Because this becomes quickly
312 /// unsustainable verification has migrated to cross signing verification.
313 ///
314 /// ## Cross signing verification
315 ///
316 /// Cross signing verification uses signatures over devices and user
317 /// identities to check if a device is considered to be verified. The
318 /// signatures can be uploaded to the homeserver, this allows us to share
319 /// the verification state with other devices. Devices only need to verify a
320 /// user identity, if the user identity has verified and signed the device
321 /// we can consider the device to be verified as well.
322 ///
323 /// Devices are usually cross signing verified using interactive
324 /// verification, which can be started using the
325 /// [`Device::request_verification()`] method.
326 ///
327 /// A [`Device`] can also be manually signed using the [`Device::verify()`]
328 /// method, this works only for devices belonging to our own user.
329 ///
330 /// Do note that the device that is being manually signed will not trust our
331 /// own user identity like it would if we interactively verify the device.
332 /// Such a device can mark our own user as verified using the
333 /// [`UserIdentity::verify()`] method.
334 ///
335 /// ### Verification of devices belonging to our own user
336 ///
337 /// If the device belongs to our own user, the device will be considered to
338 /// be verified if:
339 ///
340 /// - The device has been signed by our self-signing key
341 /// - Our own user identity is considered to be [verified]
342 ///
343 /// In other words we need to find a valid signature chain from our user
344 /// identity to the device:
345 ///
346 /// ```text
347 /// ┌─────────────────────────────────────┐ ┌─────────────┐
348 /// │ Own User Identity │ │ Device │
349 /// ├──────────────────┬──────────────────┤───►├─────────────┤
350 /// │ Master Key │ Self-signing Key │ │ Device Keys │
351 /// └──────────────────┴──────────────────┘ └─────────────┘
352 /// ```
353 ///
354 /// ### Verification of devices belonging to other users
355 ///
356 /// If the device belongs to some other user it will be considered to be
357 /// verified if:
358 ///
359 /// - The device has been signed by the user's self-signing key
360 /// - The user's master-signing key has been signed by our own user-signing
361 /// key, i.e. our own identity trusts the other users identity.
362 /// - Our own user identity is considered to be [verified]
363 ///
364 /// ```text
365 /// ┌─────────────────────────────────────┐
366 /// │ Own User Identity │
367 /// ├──────────────────┬──────────────────┤─────┐
368 /// │ Master Key │ User-signing Key │ │
369 /// └──────────────────┴──────────────────┘ │
370 /// ┌───────────────────────────────────────────────────┘
371 /// │
372 /// │ ┌─────────────────────────────────────┐ ┌─────────────┐
373 /// │ │ User Identity │ │ Device │
374 /// └──────►├──────────────────┬──────────────────┤───►│─────────────│
375 /// │ Master Key │ Self-signing Key │ │ Device Keys │
376 /// └──────────────────┴──────────────────┘ └─────────────┘
377 /// ```
378 ///
379 /// # Examples
380 ///
381 /// Let's check if a device is verified:
382 ///
383 /// ```no_run
384 /// # use matrix_sdk::{
385 /// # Client,
386 /// # ruma::{
387 /// # device_id, user_id,
388 /// # events::key::verification::VerificationMethod,
389 /// # }
390 /// # };
391 /// # use url::Url;
392 /// # async {
393 /// # let alice = user_id!("@alice:example.org");
394 /// # let homeserver = Url::parse("http://example.com")?;
395 /// # let client = Client::new(homeserver).await?;
396 /// let device =
397 /// client.encryption().get_device(alice, device_id!("DEVICEID")).await?;
398 ///
399 /// if let Some(device) = device {
400 /// if device.is_verified() {
401 /// println!(
402 /// "Device {} of user {} is verified",
403 /// device.device_id(),
404 /// device.user_id(),
405 /// );
406 /// } else {
407 /// println!(
408 /// "Device {} of user {} is not verified",
409 /// device.device_id(),
410 /// device.user_id(),
411 /// );
412 /// }
413 /// }
414 /// # anyhow::Ok(()) };
415 /// ```
416 ///
417 /// [`UserIdentity::verify()`]:
418 /// crate::encryption::identities::UserIdentity::verify
419 /// [verified]: crate::encryption::identities::UserIdentity::is_verified
420 pub fn is_verified(&self) -> bool {
421 self.inner.is_verified()
422 }
423
424 /// Is the device considered to be verified with cross-signing.
425 ///
426 /// A device is considered to be verified if it's signed by the appropriate
427 /// cross-signing key.
428 ///
429 /// ## Cross-signing verification
430 ///
431 /// Cross-signing verification uses signatures over devices and user
432 /// identities to check if a device is considered to be verified. The
433 /// signatures can be uploaded to the homeserver, this allows us to share
434 /// the verification state with other devices. Devices only need to verify a
435 /// user identity, if the user identity has verified and signed the device
436 /// we can consider the device to be verified as well.
437 ///
438 /// Devices are usually cross-signing verified using interactive
439 /// verification, which can be started using the
440 /// [`Device::request_verification()`] method.
441 ///
442 /// A [`Device`] can also be manually signed using the [`Device::verify()`]
443 /// method, this works only for devices belonging to our own user.
444 ///
445 /// Do note that the device that is being manually signed will not trust our
446 /// own user identity like it would if we interactively verify the device.
447 /// Such a device can mark our own user as verified using the
448 /// [`UserIdentity::verify()`] method.
449 ///
450 /// ### Verification of devices belonging to our own user
451 ///
452 /// If the device belongs to our own user, the device will be considered to
453 /// be verified if:
454 ///
455 /// - The device has been signed by our self-signing key
456 /// - Our own user identity is considered to be [verified]
457 ///
458 /// In other words we need to find a valid signature chain from our user
459 /// identity to the device:
460 ///
461 /// ```text
462 /// ┌─────────────────────────────────────┐ ┌─────────────┐
463 /// │ Own User Identity │ │ Device │
464 /// ├──────────────────┬──────────────────┤───►├─────────────┤
465 /// │ Master Key │ Self-signing Key │ │ Device Keys │
466 /// └──────────────────┴──────────────────┘ └─────────────┘
467 /// ```
468 ///
469 /// ### Verification of devices belonging to other users
470 ///
471 /// If the device belongs to some other user it will be considered to be
472 /// verified if:
473 ///
474 /// - The device has been signed by the user's self-signing key
475 /// - The user's master-signing key has been signed by our own user-signing
476 /// key, i.e. our own identity trusts the other users identity.
477 /// - Our own user identity is considered to be [verified]
478 ///
479 /// ```text
480 /// ┌─────────────────────────────────────┐
481 /// │ Own User Identity │
482 /// ├──────────────────┬──────────────────┤─────┐
483 /// │ Master Key │ User-signing Key │ │
484 /// └──────────────────┴──────────────────┘ │
485 /// ┌───────────────────────────────────────────────────┘
486 /// │
487 /// │ ┌─────────────────────────────────────┐ ┌─────────────┐
488 /// │ │ User Identity │ │ Device │
489 /// └──────►├──────────────────┬──────────────────┤───►│─────────────│
490 /// │ Master Key │ Self-signing Key │ │ Device Keys │
491 /// └──────────────────┴──────────────────┘ └─────────────┘
492 /// ```
493 ///
494 /// # Examples
495 ///
496 /// Let's check if a device is verified:
497 ///
498 /// ```no_run
499 /// # use matrix_sdk::{
500 /// # Client,
501 /// # ruma::{
502 /// # device_id, user_id,
503 /// # events::key::verification::VerificationMethod,
504 /// # }
505 /// # };
506 /// # use url::Url;
507 /// # async {
508 /// # let alice = user_id!("@alice:example.org");
509 /// # let homeserver = Url::parse("http://example.com")?;
510 /// # let client = Client::new(homeserver).await?;
511 /// let device =
512 /// client.encryption().get_device(alice, device_id!("DEVICEID")).await?;
513 ///
514 /// if let Some(device) = device {
515 /// if device.is_verified_with_cross_signing() {
516 /// println!(
517 /// "Device {} of user {} is verified with cross-signing",
518 /// device.device_id(),
519 /// device.user_id()
520 /// );
521 /// } else {
522 /// println!(
523 /// "Device {} of user {} is not verified with cross-signing",
524 /// device.device_id(),
525 /// device.user_id()
526 /// );
527 /// }
528 /// }
529 /// # anyhow::Ok(()) };
530 /// ```
531 ///
532 /// [`UserIdentity::verify()`]:
533 /// crate::encryption::identities::UserIdentity::verify
534 /// [verified]: crate::encryption::identities::UserIdentity::is_verified
535 pub fn is_verified_with_cross_signing(&self) -> bool {
536 self.inner.is_cross_signing_trusted()
537 }
538
539 /// Set the local trust state of the device to the given state.
540 ///
541 /// This won't affect any cross signing verification state, this only sets a
542 /// flag marking to have the given trust state.
543 ///
544 /// # Arguments
545 ///
546 /// - `trust_state` - The new trust state that should be set for the device.
547 pub async fn set_local_trust(&self, trust_state: LocalTrust) -> Result<(), CryptoStoreError> {
548 self.inner.set_local_trust(trust_state).await
549 }
550
551 /// Is the device cross-signed by its own user.
552 pub fn is_cross_signed_by_owner(&self) -> bool {
553 self.inner.is_cross_signed_by_owner()
554 }
555}
556
557/// The collection of all the [`Device`]s a user has.
558#[derive(Debug)]
559pub struct UserDevices {
560 pub(crate) inner: BaseUserDevices,
561 pub(crate) client: Client,
562}
563
564impl UserDevices {
565 /// Get the specific device with the given device ID.
566 pub fn get(&self, device_id: &DeviceId) -> Option<Device> {
567 self.inner.get(device_id).map(|d| Device { inner: d, client: self.client.clone() })
568 }
569
570 /// Iterator over all the device ids of the user devices.
571 pub fn keys(&self) -> impl Iterator<Item = &DeviceId> {
572 self.inner.keys()
573 }
574
575 /// Iterator over all the devices of the user devices.
576 pub fn devices(&self) -> impl Iterator<Item = Device> + '_ {
577 let client = self.client.clone();
578
579 self.inner.devices().map(move |d| Device { inner: d, client: client.clone() })
580 }
581}