Skip to main content

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