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