matrix_sdk_crypto/
error.rs

1// Copyright 2020 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;
16
17use matrix_sdk_common::deserialized_responses::{VerificationLevel, WithheldCode};
18use ruma::{CanonicalJsonError, IdParseError, OwnedDeviceId, OwnedRoomId, OwnedUserId};
19use serde::{ser::SerializeMap, Serializer};
20use serde_json::Error as SerdeError;
21use thiserror::Error;
22use vodozemac::{Curve25519PublicKey, Ed25519PublicKey};
23
24use super::store::CryptoStoreError;
25use crate::{olm::SessionExportError, types::SignedKey};
26#[cfg(doc)]
27use crate::{CollectStrategy, Device, LocalTrust, OtherUserIdentity};
28
29pub type OlmResult<T> = Result<T, OlmError>;
30pub type MegolmResult<T> = Result<T, MegolmError>;
31
32/// Error representing a failure during a device to device cryptographic
33/// operation.
34#[derive(Error, Debug)]
35pub enum OlmError {
36    /// The event that should have been decrypted is malformed.
37    #[error(transparent)]
38    EventError(#[from] EventError),
39
40    /// The received decrypted event couldn't be deserialized.
41    #[error(transparent)]
42    JsonError(#[from] SerdeError),
43
44    /// The received room key couldn't be converted into a valid Megolm session.
45    #[error(transparent)]
46    SessionCreation(#[from] SessionCreationError),
47
48    /// The room key that should be exported can't be converted into a
49    /// `m.forwarded_room_key` event.
50    #[error(transparent)]
51    SessionExport(#[from] SessionExportError),
52
53    /// The storage layer returned an error.
54    #[error("failed to read or write to the crypto store {0}")]
55    Store(#[from] CryptoStoreError),
56
57    /// The session with a device has become corrupted.
58    #[error(
59        "decryption failed likely because an Olm session from {0} with sender key {1} was wedged"
60    )]
61    SessionWedged(OwnedUserId, Curve25519PublicKey),
62
63    /// An Olm message got replayed while the Olm ratchet has already moved
64    /// forward.
65    #[error("decryption failed because an Olm message from {0} with sender key {1} was replayed")]
66    ReplayedMessage(OwnedUserId, Curve25519PublicKey),
67
68    /// Encryption failed because the device does not have a valid Olm session
69    /// with us.
70    #[error(
71        "encryption failed because the device does not \
72            have a valid Olm session with us"
73    )]
74    MissingSession,
75
76    /// Encryption failed due to an error collecting the recipient devices.
77    #[error("encryption failed due to an error collecting the recipient devices: {0}")]
78    SessionRecipientCollectionError(SessionRecipientCollectionError),
79}
80
81/// Error representing a failure during a group encryption operation.
82#[derive(Error, Debug)]
83pub enum MegolmError {
84    /// The event that should have been decrypted is malformed.
85    #[error(transparent)]
86    EventError(#[from] EventError),
87
88    /// The received decrypted event couldn't be deserialized.
89    #[error(transparent)]
90    JsonError(#[from] SerdeError),
91
92    /// Decryption failed because we're missing the room key that was used to
93    /// encrypt the event.
94    #[error("Can't find the room key to decrypt the event, withheld code: {0:?}")]
95    MissingRoomKey(Option<WithheldCode>),
96
97    /// Decryption failed because of a mismatch between the identity keys of the
98    /// device we received the room key from and the identity keys recorded in
99    /// the plaintext of the room key to-device message.
100    #[error(
101        "decryption failed because of mismatched identity keys of the sending device and those recorded in the to-device message"
102    )]
103    MismatchedIdentityKeys(MismatchedIdentityKeysError),
104
105    /// The encrypted megolm message couldn't be decoded.
106    #[error(transparent)]
107    Decode(#[from] vodozemac::DecodeError),
108
109    /// The event could not have been decrypted.
110    #[error(transparent)]
111    Decryption(#[from] vodozemac::megolm::DecryptionError),
112
113    /// The storage layer returned an error.
114    #[error(transparent)]
115    Store(#[from] CryptoStoreError),
116
117    /// An encrypted message wasn't decrypted, because the sender's
118    /// cross-signing identity did not satisfy the requested
119    /// [`crate::TrustRequirement`].
120    ///
121    /// The nested value is the sender's current verification level.
122    #[error("decryption failed because trust requirement not satisfied: {0}")]
123    SenderIdentityNotTrusted(VerificationLevel),
124}
125
126/// Decryption failed because of a mismatch between the identity keys of the
127/// device we received the room key from and the identity keys recorded in
128/// the plaintext of the room key to-device message.
129#[derive(Error, Debug, PartialEq)]
130pub struct MismatchedIdentityKeysError {
131    /// The Ed25519 key recorded in the room key's to-device message.
132    pub key_ed25519: Box<Ed25519PublicKey>,
133    /// The Ed25519 identity key of the device sending the room key.
134    pub device_ed25519: Option<Box<Ed25519PublicKey>>,
135    /// The Curve25519 key recorded in the room key's to-device message.
136    pub key_curve25519: Box<Curve25519PublicKey>,
137    /// The Curve25519 identity key of the device sending the room key.
138    pub device_curve25519: Option<Box<Curve25519PublicKey>>,
139}
140
141impl std::fmt::Display for MismatchedIdentityKeysError {
142    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
143        let mut ser = f.serialize_struct("MismatchedIdentityKeysError", 4)?;
144        ser.serialize_entry("key_ed25519", &self.key_ed25519)?;
145        ser.serialize_entry("device_ed25519", &self.device_ed25519)?;
146        ser.serialize_entry("key_curve25519", &self.key_curve25519)?;
147        ser.serialize_entry("device_curve25519", &self.device_curve25519)?;
148        ser.end()
149    }
150}
151
152impl From<MismatchedIdentityKeysError> for MegolmError {
153    fn from(value: MismatchedIdentityKeysError) -> Self {
154        MegolmError::MismatchedIdentityKeys(value)
155    }
156}
157
158impl From<MismatchedIdentityKeysError> for SessionCreationError {
159    fn from(value: MismatchedIdentityKeysError) -> Self {
160        SessionCreationError::MismatchedIdentityKeys(value)
161    }
162}
163
164/// Error that occurs when decrypting an event that is malformed.
165#[derive(Error, Debug)]
166pub enum EventError {
167    /// The Encrypted message has been encrypted with a unsupported algorithm.
168    #[error("the Encrypted message has been encrypted with a unsupported algorithm.")]
169    UnsupportedAlgorithm,
170
171    /// The provided JSON value isn't an object.
172    #[error("the provided JSON value isn't an object")]
173    NotAnObject,
174
175    /// The Encrypted message doesn't contain a ciphertext for our device.
176    #[error("the Encrypted message doesn't contain a ciphertext for our device")]
177    MissingCiphertext,
178
179    /// The Encrypted message is missing the signing key of the sender.
180    #[error("the Encrypted message is missing the signing key of the sender")]
181    MissingSigningKey,
182
183    /// The Encrypted message is missing the sender key.
184    #[error("the Encrypted message is missing the sender key")]
185    MissingSenderKey,
186
187    /// The sender of the plaintext doesn't match the sender of the encrypted
188    /// message.
189    #[error(
190        "the sender of the plaintext doesn't match the sender of the encrypted \
191        message, got {0}, expected {1}"
192    )]
193    MismatchedSender(OwnedUserId, OwnedUserId),
194
195    /// The public key that was part of the message doesn't match the key we
196    /// have stored.
197    #[error(
198        "the public key that was part of the message doesn't match the key we \
199        have stored, expected {0}, got {1}"
200    )]
201    MismatchedKeys(Box<Ed25519PublicKey>, Box<Ed25519PublicKey>),
202
203    /// The room ID of the room key doesn't match the room ID of the decrypted
204    /// event.
205    #[error(
206        "the room id of the room key doesn't match the room id of the \
207        decrypted event: expected {0}, got {1:?}"
208    )]
209    MismatchedRoom(OwnedRoomId, Option<OwnedRoomId>),
210}
211
212/// Error type describing different errors that can happen when we create an
213/// Olm session from a pickle.
214#[derive(Error, Debug)]
215pub enum SessionUnpickleError {
216    /// The device keys are missing the signing key
217    #[error("the device keys are missing the signing key")]
218    MissingSigningKey,
219
220    /// The device keys are missing the identity key
221    #[error("the device keys are missing the identity key")]
222    MissingIdentityKey,
223}
224
225/// Error type describing different errors that happen when we check or create
226/// signatures for a Matrix JSON object.
227#[derive(Error, Debug)]
228pub enum SignatureError {
229    /// The signature was made using an unsupported algorithm.
230    #[error("the signature used an unsupported algorithm")]
231    UnsupportedAlgorithm,
232
233    /// The ID of the signing key isn't a valid key ID.
234    #[error("the ID of the signing key is invalid")]
235    InvalidKeyId(#[from] IdParseError),
236
237    /// The signing key that should create or check a signature is missing.
238    #[error("the signing key is missing from the object that signed the message")]
239    MissingSigningKey,
240
241    /// The user id of signing key differs from the user id that provided the
242    /// signature.
243    #[error("the user id of the signing key differs user id that provided the signature")]
244    UserIdMismatch,
245
246    /// The provided JSON value that was signed and the signature should be
247    /// checked isn't a valid JSON object.
248    #[error("the provided JSON value isn't an object")]
249    NotAnObject,
250
251    /// The provided JSON value that was signed and the signature should be
252    /// checked isn't a valid JSON object.
253    #[error("the provided JSON object doesn't contain a signatures field")]
254    NoSignatureFound,
255
256    /// The signature couldn't be verified.
257    #[error(transparent)]
258    VerificationError(#[from] vodozemac::SignatureError),
259
260    /// The public key isn't a valid ed25519 key.
261    #[error(transparent)]
262    InvalidKey(#[from] vodozemac::KeyError),
263
264    /// The signature could not be decoded.
265    #[error("the given signature is not valid and can't be decoded")]
266    InvalidSignature,
267
268    /// The signing key that used to sign the object has been changed.
269    #[error("the signing key that used to sign the object has changed, old: {0:?}, new: {1:?}")]
270    SigningKeyChanged(Option<Box<Ed25519PublicKey>>, Option<Box<Ed25519PublicKey>>),
271
272    /// The signed object couldn't be deserialized.
273    #[error(transparent)]
274    JsonError(#[from] CanonicalJsonError),
275
276    /// The store ran into an error.
277    #[error(transparent)]
278    StoreError(#[from] CryptoStoreError),
279}
280
281impl From<SerdeError> for SignatureError {
282    fn from(e: SerdeError) -> Self {
283        CanonicalJsonError::SerDe(e).into()
284    }
285}
286
287/// Error that occurs when a room key can't be converted into a valid Megolm
288/// session.
289#[derive(Error, Debug)]
290pub enum SessionCreationError {
291    /// The requested one-time key isn't a signed curve key.
292    #[error(
293        "Failed to create a new Olm session for {0} {1}, the requested \
294        one-time key isn't a signed curve key"
295    )]
296    OneTimeKeyNotSigned(OwnedUserId, OwnedDeviceId),
297
298    /// The signed one-time key is missing.
299    #[error(
300        "Tried to create a new Olm session for {0} {1}, but the signed \
301        one-time key is missing"
302    )]
303    OneTimeKeyMissing(OwnedUserId, OwnedDeviceId),
304
305    /// Failed to verify the one-time key signatures.
306    #[error(
307        "Failed to verify the signature of a one-time key, key: {one_time_key:?}, \
308        signing_key: {signing_key:?}: {error:?}"
309    )]
310    InvalidSignature {
311        /// The one-time key that failed the signature verification.
312        one_time_key: Box<SignedKey>,
313        /// The key that was used to verify the signature.
314        signing_key: Option<Box<Ed25519PublicKey>>,
315        /// The exact error describing why the signature verification failed.
316        error: Box<SignatureError>,
317    },
318
319    /// The user's device is missing a curve25519 key.
320    #[error(
321        "Tried to create an Olm session for {0} {1}, but the device is missing \
322        a curve25519 key"
323    )]
324    DeviceMissingCurveKey(OwnedUserId, OwnedDeviceId),
325
326    /// Error deserializing the one-time key.
327    #[error("Error deserializing the one-time key: {0}")]
328    InvalidJson(#[from] serde_json::Error),
329
330    /// The given curve25519 key is not a valid key.
331    #[error("The given curve25519 key is not a valid key")]
332    InvalidCurveKey(#[from] vodozemac::KeyError),
333
334    /// Error when creating an Olm Session from an incoming Olm message.
335    #[error(transparent)]
336    InboundCreation(#[from] vodozemac::olm::SessionCreationError),
337
338    /// The given device keys are invalid.
339    #[error("The given device keys are invalid")]
340    InvalidDeviceKeys(#[from] SignatureError),
341
342    /// There was a mismatch between the identity keys of the device we received
343    /// the room key from and the identity keys recorded in the plaintext of the
344    /// room key to-device message.
345    #[error(
346        "There was a mismatch between the identity keys of the sending device \
347        and those recorded in the to-device message"
348    )]
349    MismatchedIdentityKeys(MismatchedIdentityKeysError),
350}
351
352/// Errors that can be returned by
353/// [`crate::machine::OlmMachine::set_room_settings`].
354#[derive(Debug, Error)]
355pub enum SetRoomSettingsError {
356    /// The changes are rejected because they conflict with the previous
357    /// settings for this room.
358    #[error("the new settings would cause a downgrade of encryption security")]
359    EncryptionDowngrade,
360
361    /// The changes are rejected because we would be unable to use them to
362    /// encrypt events.
363    #[error("the new settings are invalid")]
364    InvalidSettings,
365
366    /// The store ran into an error.
367    #[error(transparent)]
368    Store(#[from] CryptoStoreError),
369}
370
371/// Error representing a problem when collecting the recipient devices for the
372/// room key, during an encryption operation.
373#[derive(Error, Debug)]
374pub enum SessionRecipientCollectionError {
375    /// One or more verified users has one or more unsigned devices.
376    ///
377    /// Happens only with [`CollectStrategy::ErrorOnVerifiedUserProblem`].
378    ///
379    /// In order to resolve this, the caller can set the trust level of the
380    /// affected devices to [`LocalTrust::Ignored`] or
381    /// [`LocalTrust::BlackListed`] (see [`Device::set_local_trust`]), and
382    /// then retry the encryption operation.
383    #[error("one or more verified users have unsigned devices")]
384    VerifiedUserHasUnsignedDevice(BTreeMap<OwnedUserId, Vec<OwnedDeviceId>>),
385
386    /// One or more users was previously verified, but they have changed their
387    /// identity.
388    ///
389    /// Happens only with [`CollectStrategy::ErrorOnVerifiedUserProblem`] or
390    /// [`CollectStrategy::IdentityBasedStrategy`].
391    ///
392    /// In order to resolve this, the user can:
393    ///
394    /// * re-verify the problematic recipients, or
395    ///
396    /// * withdraw verification of the problematic recipients with
397    ///   [`OtherUserIdentity::withdraw_verification`], or
398    ///
399    /// * set the trust level of all of the devices belonging to the problematic
400    ///   recipients to [`LocalTrust::Ignored`] or [`LocalTrust::BlackListed`]
401    ///   (see [`Device::set_local_trust`]).
402    ///
403    /// The caller can then retry the encryption operation.
404    #[error("one or more users that were verified have changed their identity")]
405    VerifiedUserChangedIdentity(Vec<OwnedUserId>),
406
407    /// Cross-signing has not been configured on our own identity.
408    ///
409    /// Happens only with [`CollectStrategy::IdentityBasedStrategy`].
410    /// (Cross-signing is required for encryption when using
411    /// `IdentityBasedStrategy`.) Apps should detect this condition and prevent
412    /// sending in the UI rather than waiting for this error to be returned when
413    /// encrypting.
414    #[error("Encryption failed because cross-signing is not set up on your account")]
415    CrossSigningNotSetup,
416
417    /// The current device has not been cross-signed by our own identity.
418    ///
419    /// Happens only with [`CollectStrategy::IdentityBasedStrategy`].
420    /// (Cross-signing is required for encryption when using
421    /// `IdentityBasedStrategy`.) Apps should detect this condition and prevent
422    /// sending in the UI rather than waiting for this error to be returned when
423    /// encrypting.
424    #[error("Encryption failed because your device is not verified")]
425    SendingFromUnverifiedDevice,
426}