Skip to main content

openmls/group/
errors.rs

1//! # MLS group errors
2//!
3//! This module contains errors that originate at lower levels and are partially re-exported in errors thrown by functions of the `MlsGroup` API.
4
5use openmls_traits::types::Ciphersuite;
6use thiserror::Error;
7
8#[cfg(feature = "extensions-draft")]
9use super::public_group::errors::ApplyAppDataUpdateError;
10
11pub use super::mls_group::errors::*;
12use super::public_group::errors::CreationFromExternalError;
13use crate::{
14    ciphersuite::signable::SignatureError,
15    error::LibraryError,
16    extensions::errors::{ExtensionError, InvalidExtensionError},
17    framing::errors::MessageDecryptionError,
18    group::commit_builder::external_commits::ExternalCommitBuilderError,
19    key_packages::errors::{KeyPackageExtensionSupportError, KeyPackageVerifyError},
20    messages::{group_info::GroupInfoError, GroupSecretsError},
21    prelude::ExtensionType,
22    schedule::{
23        errors::{KeyScheduleError, PskError},
24        PreSharedKeyId,
25    },
26    treesync::errors::*,
27};
28
29#[cfg(doc)]
30use crate::{group::GroupId, treesync::LeafNodeParameters};
31
32/// Welcome error
33#[derive(Error, Debug, PartialEq, Clone)]
34pub enum WelcomeError<StorageError> {
35    /// See [`GroupSecretsError`] for more details.
36    #[error(transparent)]
37    GroupSecrets(#[from] GroupSecretsError),
38    /// Private part of `init_key` not found in key store.
39    #[error("Private part of `init_key` not found in key store.")]
40    PrivateInitKeyNotFound,
41    /// See [`LibraryError`] for more details.
42    #[error(transparent)]
43    LibraryError(#[from] LibraryError),
44    /// Ciphersuites in Welcome and key package bundle don't match.
45    #[error("Ciphersuites in Welcome and key package bundle don't match.")]
46    CiphersuiteMismatch,
47    /// See [`GroupInfoError`] for more details.
48    #[error(transparent)]
49    GroupInfo(#[from] GroupInfoError),
50    /// No joiner secret found in the Welcome message.
51    #[error("No joiner secret found in the Welcome message.")]
52    JoinerSecretNotFound,
53    /// No ratchet tree available to build initial tree after receiving a Welcome message.
54    #[error("No ratchet tree available to build initial tree after receiving a Welcome message.")]
55    MissingRatchetTree,
56    /// The computed confirmation tag does not match the expected one.
57    #[error("The computed confirmation tag does not match the expected one.")]
58    ConfirmationTagMismatch,
59    /// The signature on the GroupInfo is not valid.
60    #[error("The signature on the GroupInfo is not valid.")]
61    InvalidGroupInfoSignature,
62    /// We don't support the version of the group we are trying to join.
63    #[error("We don't support the version of the group we are trying to join.")]
64    UnsupportedMlsVersion,
65    /// We don't support all capabilities of the group.
66    #[error("We don't support all capabilities of the group.")]
67    UnsupportedCapability,
68    /// The crypto provider doesn't support the ciphersuite of the group we are trying to join.
69    #[error("Ciphersuite {0:?} of the group we are trying to join is not supported by the crypto provider.")]
70    UnsupportedCiphersuite(Ciphersuite),
71    /// Sender not found in tree.
72    #[error("Sender not found in tree.")]
73    UnknownSender,
74    /// The provided message is not a Welcome message.
75    #[error("Not a Welcome message.")]
76    NotAWelcomeMessage,
77    /// Malformed Welcome message.
78    #[error("Malformed Welcome message.")]
79    MalformedWelcomeMessage,
80    /// Could not decrypt the Welcome message.
81    #[error("Could not decrypt the Welcome message.")]
82    UnableToDecrypt,
83    /// Unsupported extensions found in the GroupContext or KeyPackage of another member.
84    #[error("Unsupported extensions found in the GroupContext or KeyPackage of another member.")]
85    UnsupportedExtensions,
86    /// See [`PskError`] for more details.
87    #[error(transparent)]
88    Psk(#[from] PskError),
89    /// No matching encryption key was found in the key store.
90    #[error("No matching encryption key was found in the key store.")]
91    NoMatchingEncryptionKey,
92    /// No matching key package was found in the key store.
93    #[error("No matching key package was found in the key store.")]
94    NoMatchingKeyPackage,
95    /// This error indicates the public tree is invalid. See [`PublicTreeError`] for more details.
96    #[error(transparent)]
97    PublicTreeError(#[from] PublicTreeError),
98    /// This error indicates the public tree is invalid. See
99    /// [`CreationFromExternalError`] for more details.
100    #[error(transparent)]
101    PublicGroupError(#[from] CreationFromExternalError<StorageError>),
102    /// This error indicates the leaf node is invalid. See [`LeafNodeValidationError`] for more details.
103    #[error(transparent)]
104    LeafNodeValidation(#[from] LeafNodeValidationError),
105    /// This error indicates that an error occurred while reading or writing from/to storage.
106    #[error("An error occurred when querying storage")]
107    StorageError(StorageError),
108    /// A group with this [`GroupId`] already exists.
109    #[error("A group with this [`GroupId`] already exists.")]
110    GroupAlreadyExists,
111    /// A virtual-clients error occurred while deriving or validating the
112    /// virtual client's join material.
113    #[cfg(feature = "virtual-clients-draft")]
114    #[error(transparent)]
115    VirtualClientsError(#[from] crate::components::vc_derivation_info::VirtualClientsError),
116    /// The joined group is an emulation group, and registering the derivation
117    /// epoch of the Welcome's output epoch failed.
118    #[cfg(feature = "virtual-clients-draft")]
119    #[error(transparent)]
120    RegisterVcDerivationEpoch(#[from] crate::group::RegisterVcDerivationEpochError<StorageError>),
121    /// This error indicates that computing the key schedule failed
122    #[error(transparent)]
123    KeySchedule(#[from] KeyScheduleError),
124    /// The subgroup's protocol version or ciphersuite does not match the parent
125    /// group (RFC 9420 §11.3).
126    #[error("The subgroup's protocol version or ciphersuite does not match the parent group.")]
127    SubgroupParameterMismatch,
128    /// The subgroup is not at epoch 1, as required for a branched subgroup
129    /// (RFC 9420 §11.3).
130    #[error("The subgroup is not at epoch 1.")]
131    SubgroupEpochInvalid,
132    /// A member of the subgroup does not match any member of the parent group
133    /// (RFC 9420 §11.3).
134    #[error("A member of the subgroup does not match any member of the parent group.")]
135    SubgroupLeafMismatch,
136    /// The parent group or epoch referenced by the subgroup's branch PSK does not
137    /// match the provided parent group information (RFC 9420 §11.3).
138    #[error("The subgroup's branch PSK does not reference the provided parent group/epoch.")]
139    SubgroupParentMismatch,
140}
141
142/// External Commit error
143#[derive(Error, Debug, PartialEq, Clone)]
144pub enum ExternalCommitError<StorageError> {
145    /// See [`LibraryError`] for more details.
146    #[error(transparent)]
147    LibraryError(#[from] LibraryError),
148    /// No ratchet tree available to build initial tree.
149    #[error("No ratchet tree available to build initial tree.")]
150    MissingRatchetTree,
151    /// No external_pub extension available to join group by external commit.
152    #[error("No external_pub extension available to join group by external commit.")]
153    MissingExternalPub,
154    /// We don't support the ciphersuite of the group we are trying to join.
155    #[error("Ciphersuite {0:?} of the group we are trying to join is not supported by the crypto provider.")]
156    UnsupportedCiphersuite(Ciphersuite),
157    /// Sender not found in tree.
158    #[error("Sender not found in tree.")]
159    UnknownSender,
160    /// The signature over the given group info is invalid.
161    #[error("The signature over the given group info is invalid.")]
162    InvalidGroupInfoSignature,
163    /// Error creating external commit.
164    #[error("Error creating external commit.")]
165    CommitError(#[from] CreateCommitError),
166    /// This error indicates the public tree is invalid. See
167    /// [`CreationFromExternalError`] for more details.
168    #[error(transparent)]
169    PublicGroupError(#[from] CreationFromExternalError<StorageError>),
170    /// Credential is missing from external commit.
171    #[error("Credential is missing from external commit.")]
172    MissingCredential,
173    /// An erorr occurred when writing group to storage
174    #[error("An error occurred when writing group to storage.")]
175    StorageError(StorageError),
176}
177
178impl<StorageError> From<ExternalCommitBuilderError<StorageError>>
179    for ExternalCommitError<StorageError>
180{
181    fn from(error: ExternalCommitBuilderError<StorageError>) -> Self {
182        match error {
183            ExternalCommitBuilderError::LibraryError(library_error) => {
184                ExternalCommitError::LibraryError(library_error)
185            }
186            ExternalCommitBuilderError::MissingRatchetTree => {
187                ExternalCommitError::MissingRatchetTree
188            }
189            ExternalCommitBuilderError::MissingExternalPub => {
190                ExternalCommitError::MissingExternalPub
191            }
192            ExternalCommitBuilderError::UnsupportedCiphersuite(ciphersuite) => {
193                ExternalCommitError::UnsupportedCiphersuite(ciphersuite)
194            }
195            ExternalCommitBuilderError::PublicGroupError(creation_from_external_error) => {
196                ExternalCommitError::PublicGroupError(creation_from_external_error)
197            }
198            ExternalCommitBuilderError::StorageError(error) => {
199                ExternalCommitError::StorageError(error)
200            }
201            // These should not happen since `join_by_external_commit` doesn't
202            // take proposals as input.
203            ExternalCommitBuilderError::InvalidProposal(e) => {
204                log::error!("Error validating proposal in external commit: {e}");
205                ExternalCommitError::LibraryError(LibraryError::custom(
206                    "Error creating external commit",
207                ))
208            }
209        }
210    }
211}
212
213/// Error joining a higher-level group as a virtual client's sibling emulator
214/// by processing another sibling's external commit
215/// ([`VcExternalCommitJoinBuilder`]).
216///
217/// [`VcExternalCommitJoinBuilder`]: crate::group::VcExternalCommitJoinBuilder
218#[cfg(feature = "virtual-clients-draft")]
219#[derive(Error, Debug)]
220pub enum VcExternalCommitJoinError<StorageError> {
221    /// See [`LibraryError`] for more details.
222    #[error(transparent)]
223    LibraryError(#[from] LibraryError),
224    /// No ratchet tree available to build the prior-epoch public group.
225    #[error("No ratchet tree available to build the prior-epoch public group.")]
226    MissingRatchetTree,
227    /// The prior-epoch public tree is invalid. See [`CreationFromExternalError`].
228    #[error(transparent)]
229    PublicGroupError(#[from] CreationFromExternalError<StorageError>),
230    /// The external commit could not be parsed or verified.
231    #[error(transparent)]
232    ProcessMessageError(#[from] ProcessMessageError<StorageError>),
233    /// Staging the external commit failed.
234    #[error(transparent)]
235    StageCommitError(#[from] StageCommitError),
236    /// Merging the external commit failed.
237    #[error(transparent)]
238    MergeCommitError(#[from] MergeCommitError<StorageError>),
239    /// The message is not an external commit (`Sender::NewMemberCommit` with a
240    /// Commit body).
241    #[error("The message is not an external commit.")]
242    NotAnExternalCommit,
243    /// The external commit's leaf carries no virtual-clients derivation info,
244    /// so a sibling cannot reconstruct the joining state from it.
245    #[error("The external commit carries no virtual-clients derivation info.")]
246    MissingDerivationInfo,
247    /// The derivation info references a different derivation epoch than the one
248    /// supplied.
249    #[error("The external commit references a different derivation epoch.")]
250    EpochIdMismatch,
251    /// A virtual-clients processing error occurred.
252    #[error(transparent)]
253    VirtualClientsError(#[from] crate::components::vc_derivation_info::VirtualClientsError),
254    /// An error occurred when writing the group to storage.
255    #[error("An error occurred when writing the group to storage.")]
256    StorageError(StorageError),
257}
258
259/// Error bootstrapping a virtual client's sibling emulator into a higher-level
260/// group the virtual client created, by processing the creator's initial group
261/// creation material ([`MlsGroup::vc_join_at_creation`]).
262///
263/// [`MlsGroup::vc_join_at_creation`]: crate::group::MlsGroup::vc_join_at_creation
264#[cfg(feature = "virtual-clients-draft")]
265#[derive(Error, Debug)]
266pub enum VcGroupCreationJoinError<StorageError> {
267    /// See [`LibraryError`] for more details.
268    #[error(transparent)]
269    LibraryError(#[from] LibraryError),
270    /// No ratchet tree available to build the created group's public tree.
271    #[error("No ratchet tree available to build the created group's public tree.")]
272    MissingRatchetTree,
273    /// The created group's public tree is invalid. See
274    /// [`CreationFromExternalError`].
275    #[error(transparent)]
276    PublicGroupError(#[from] CreationFromExternalError<StorageError>),
277    /// The ratchet tree does not consist of exactly the creator's leaf.
278    #[error("The ratchet tree does not consist of exactly the creator's leaf.")]
279    NotASingleLeafTree,
280    /// The creator leaf carries no virtual-clients derivation info.
281    #[error("The creator leaf carries no virtual-clients derivation info.")]
282    MissingDerivationInfo,
283    /// The derivation info references a different derivation epoch than the one
284    /// supplied.
285    #[error("The creator leaf references a different derivation epoch.")]
286    EpochIdMismatch,
287    /// The creator leaf is not `key_package`-sourced, so it is not a virtual
288    /// client's group-creation leaf.
289    #[error("The creator leaf is not key_package-sourced.")]
290    CreatorLeafNotKeyPackageSourced,
291    /// The leaf key material derived from the operation secret does not match
292    /// the creator leaf, so this is not a genuine sibling-created group.
293    #[error("The derived leaf key material does not match the creator leaf.")]
294    LeafKeyMismatch,
295    /// The GroupInfo could not be verified against the reconstructed epoch
296    /// state, so the reconstruction did not reproduce the creator's secrets.
297    #[error("The GroupInfo could not be verified against the reconstructed epoch state.")]
298    ConfirmationTagMismatch,
299    /// A virtual-clients processing error occurred.
300    #[error(transparent)]
301    VirtualClientsError(#[from] crate::components::vc_derivation_info::VirtualClientsError),
302    /// An error occurred when writing the group to storage.
303    #[error("An error occurred when writing the group to storage.")]
304    StorageError(StorageError),
305}
306
307impl<StorageError> From<ExternalCommitBuilderFinalizeError<StorageError>>
308    for ExternalCommitError<StorageError>
309{
310    fn from(error: ExternalCommitBuilderFinalizeError<StorageError>) -> Self {
311        match error {
312            ExternalCommitBuilderFinalizeError::LibraryError(library_error) => {
313                ExternalCommitError::LibraryError(library_error)
314            }
315            ExternalCommitBuilderFinalizeError::StorageError(error) => {
316                ExternalCommitError::StorageError(error)
317            }
318            ExternalCommitBuilderFinalizeError::MergeCommitError(e) => {
319                log::error!("Error merging external commit: {e}");
320                // This shouldn't happen, since we merge our own external
321                // commit.
322                ExternalCommitError::LibraryError(LibraryError::custom(
323                    "Error merging external commit",
324                ))
325            }
326        }
327    }
328}
329
330/// Stage Commit error
331#[derive(Error, Debug, PartialEq, Clone)]
332pub enum StageCommitError {
333    /// Virtual clients error.
334    #[cfg(feature = "virtual-clients-draft")]
335    #[error(transparent)]
336    VirtualClientsError(#[from] crate::components::vc_derivation_info::VirtualClientsError),
337    /// The commit's virtual-clients Safe AAD item, or the Safe AAD carrying it,
338    /// did not parse. The item decides whether the commit's output epoch is a
339    /// derivation epoch, so an emulation group cannot fall back to a guess.
340    /// Groups that are not emulation groups never read the item.
341    #[cfg(feature = "virtual-clients-draft")]
342    #[error("The commit's virtual-clients Safe AAD item did not parse: {0}")]
343    MalformedVcCommitData(String),
344    /// See [`LibraryError`] for more details.
345    #[error(transparent)]
346    LibraryError(#[from] LibraryError),
347    /// The epoch of the group context and PublicMessage didn't match.
348    #[error("The epoch of the group context and PublicMessage didn't match.")]
349    EpochMismatch,
350    /// The Commit was created by this client but does not match the pending commit.
351    #[error("The Commit was created by this client but does not match the pending commit.")]
352    OwnCommitMismatch,
353    /// stage_commit was called with an PublicMessage that is not a Commit.
354    #[error("stage_commit was called with an PublicMessage that is not a Commit.")]
355    WrongPlaintextContentType,
356    /// Unable to verify the leaf node signature.
357    #[error("Unable to verify the leaf node signature.")]
358    PathLeafNodeVerificationFailure,
359    /// Unable to determine commit path.
360    #[error("Unable to determine commit path.")]
361    RequiredPathNotFound,
362    /// The confirmation Tag is missing.
363    #[error("The confirmation Tag is missing.")]
364    ConfirmationTagMissing,
365    /// The confirmation tag is invalid.
366    #[error("The confirmation tag is invalid.")]
367    ConfirmationTagMismatch,
368    /// The committer can't remove themselves.
369    #[error("The committer can't remove themselves.")]
370    AttemptedSelfRemoval,
371    /// The proposal queue is missing a proposal for the commit.
372    #[error("The proposal queue is missing a proposal for the commit.")]
373    MissingProposal,
374    /// Missing own key to apply proposal.
375    #[error("Missing own key to apply proposal.")]
376    OwnKeyNotFound,
377    /// External Committer used the wrong index.
378    #[error("External Committer used the wrong index.")]
379    InconsistentSenderIndex,
380    /// The sender is of type external, which is not valid.
381    #[error("The sender is of type external, which is not valid.")]
382    SenderTypeExternal,
383    /// The sender is of type `NewMemberProposal`, which is not valid.
384    #[error("The sender is of type NewMemberProposal, which is not valid.")]
385    SenderTypeNewMemberProposal,
386    /// Too many new members: the tree is full.
387    #[error("Too many new members: the tree is full.")]
388    TooManyNewMembers,
389    /// See [`ProposalValidationError`] for more details.
390    #[error(transparent)]
391    ProposalValidationError(#[from] ProposalValidationError),
392    /// See [`PskError`] for more details.
393    #[error(transparent)]
394    PskError(#[from] PskError),
395    /// See [`ExternalCommitValidationError`] for more details.
396    #[error(transparent)]
397    ExternalCommitValidation(#[from] ExternalCommitValidationError),
398    /// See [`ApplyUpdatePathError`] for more details.
399    #[error(transparent)]
400    UpdatePathError(#[from] ApplyUpdatePathError),
401    /// Missing decryption key.
402    #[error("Missing decryption key.")]
403    MissingDecryptionKey,
404    /// See [`UpdatePathError`] for more details.
405    #[error(transparent)]
406    VerifiedUpdatePathError(#[from] UpdatePathError),
407    /// See [`GroupContextExtensionsProposalValidationError`] for more details.
408    #[error(transparent)]
409    GroupContextExtensionsProposalValidationError(
410        #[from] GroupContextExtensionsProposalValidationError,
411    ),
412    #[cfg(feature = "extensions-draft")]
413    /// See [`AppDataUpdateValidationError`] for more details.
414    #[error(transparent)]
415    AppDataUpdateValidationError(#[from] AppDataUpdateValidationError),
416    /// See [`LeafNodeValidationError`] for more details.
417    #[error(transparent)]
418    LeafNodeValidation(#[from] LeafNodeValidationError),
419    /// See [`ApplyAppDataUpdateError`] for more details.
420    #[cfg(feature = "extensions-draft")]
421    #[error(transparent)]
422    ApplyAppDataUpdateError(#[from] ApplyAppDataUpdateError),
423    /// Duplicate PSK Proposal.
424    #[error("Duplicate PSK proposal with PSK ID {0:?}.")]
425    DuplicatePskId(PreSharedKeyId),
426}
427
428/// Create commit error
429#[derive(Error, Debug, PartialEq, Clone)]
430pub enum CreateCommitError {
431    /// See [`LibraryError`] for more details.
432    #[error(transparent)]
433    LibraryError(#[from] LibraryError),
434    /// Virtual-clients error.
435    #[cfg(feature = "virtual-clients-draft")]
436    #[error(transparent)]
437    VirtualClientsError(#[from] crate::components::vc_derivation_info::VirtualClientsError),
438    /// See [`VcCommitDataError`](crate::components::vc_commit_data::VcCommitDataError)
439    /// for more details.
440    #[cfg(feature = "virtual-clients-draft")]
441    #[error(transparent)]
442    VcCommitData(#[from] crate::components::vc_commit_data::VcCommitDataError),
443    /// A new derivation epoch was requested, but the group's GroupContext does
444    /// not require Safe AAD framing, so the commit cannot carry the marker.
445    #[cfg(feature = "virtual-clients-draft")]
446    #[error("A new derivation epoch requires the group to use Safe AAD framing.")]
447    NewDerivationEpochWithoutSafeAad,
448    /// A new derivation epoch was requested in a group that is not configured
449    /// as an emulation group. The sender would broadcast the marker without
450    /// registering the epoch itself, desynchronizing the emulator clients.
451    #[cfg(feature = "virtual-clients-draft")]
452    #[error("A new derivation epoch can only be requested in an emulation group.")]
453    NewDerivationEpochOutsideEmulationGroup,
454    /// Missing own key to apply proposal.
455    #[error("Missing own key to apply proposal.")]
456    OwnKeyNotFound,
457    /// The Commit tried to remove self from the group. This is not possible.
458    #[error("The Commit tried to remove self from the group. This is not possible.")]
459    CannotRemoveSelf,
460    /// The proposal queue is missing a proposal for the commit.
461    #[error("The proposal queue is missing a proposal for the commit.")]
462    MissingProposal,
463    /// A proposal has the wrong sender type.
464    #[error("A proposal has the wrong sender type.")]
465    WrongProposalSenderType,
466    /// See [`PskError`] for more details.
467    #[error(transparent)]
468    PskError(#[from] PskError),
469    /// See [`ProposalValidationError`] for more details.
470    #[error(transparent)]
471    ProposalValidationError(#[from] ProposalValidationError),
472    /// See [`SignatureError`] for more details.
473    #[error(transparent)]
474    SignatureError(#[from] SignatureError),
475    /// Credential is missing from external commit.
476    #[error("Credential is missing from external commit.")]
477    MissingCredential,
478    /// This error indicates the public tree is invalid. See [`PublicTreeError`] for more details.
479    #[error(transparent)]
480    PublicTreeError(#[from] PublicTreeError),
481    /// See [`InvalidExtensionError`] for more details.
482    #[error(transparent)]
483    InvalidExtensionError(#[from] InvalidExtensionError),
484    #[cfg(feature = "extensions-draft")]
485    /// See [`AppDataUpdateValidationError`] for more details.
486    #[error(transparent)]
487    AppDataUpdateValidationError(#[from] AppDataUpdateValidationError),
488    /// See [`GroupContextExtensionsProposalValidationError`] for more details.
489    #[error(transparent)]
490    GroupContextExtensionsProposalValidationError(
491        #[from] GroupContextExtensionsProposalValidationError,
492    ),
493    /// See [`TreeSyncAddLeaf`] for more details.
494    #[error(transparent)]
495    TreeSyncAddLeaf(#[from] TreeSyncAddLeaf),
496    /// Invalid [`LeafNodeParameters`]. `[CredentialWithKey]` can't be set with new signer.
497    #[error("Invalid LeafNodeParameters. CredentialWithKey can't be set with new signer.")]
498    InvalidLeafNodeParameters,
499    /// The new signer's signature scheme does not match the group's ciphersuite.
500    #[error("The new signer's signature scheme does not match the group's ciphersuite.")]
501    InvalidSignerCiphersuite,
502    /// A new signer cannot be used with an external commit.
503    #[error("A new signer cannot be used with an external commit. The credential and signer are the ones passed to the external commit builder.")]
504    ExternalCommitWithNewSigner,
505    /// The credential in the [`LeafNodeParameters`] differs from the external commit credential.
506    #[error("The credential in the LeafNodeParameters differs from the one passed to the external commit builder.")]
507    ExternalCommitCredentialMismatch,
508    /// Invalid external commit.
509    #[error("Invalid external commit.")]
510    InvalidExternalCommit(#[from] ExternalCommitValidationError),
511    /// See [`ApplyAppDataUpdateError`] for more details.
512    #[cfg(feature = "extensions-draft")]
513    #[error(transparent)]
514    ApplyAppDataUpdateError(#[from] ApplyAppDataUpdateError),
515    /// See [`LeafNodeValidationError`] for more details.
516    #[error(transparent)]
517    LeafNodeValidation(#[from] LeafNodeValidationError),
518}
519
520/// Stage commit error
521#[derive(Error, Debug, PartialEq, Clone)]
522pub enum CommitBuilderStageError<StorageError> {
523    /// See [`LibraryError`] for more details.
524    #[error(transparent)]
525    LibraryError(#[from] LibraryError),
526    /// Error interacting with storage.
527    #[error("Error interacting with storage.")]
528    KeyStoreError(StorageError),
529}
530
531/// Stage commit error
532#[derive(Error, Debug, PartialEq, Clone)]
533pub enum ExternalCommitBuilderFinalizeError<StorageError> {
534    /// See [`LibraryError`] for more details.
535    #[error(transparent)]
536    LibraryError(#[from] LibraryError),
537    /// Error interacting with storage.
538    #[error("Error interacting with storage.")]
539    StorageError(StorageError),
540    /// Error merging external commit.
541    #[error("Error merging external commit.")]
542    MergeCommitError(#[from] MergePendingCommitError<StorageError>),
543}
544
545/// Validation error
546#[derive(Error, Debug, PartialEq, Clone)]
547pub enum ValidationError {
548    /// See [`LibraryError`] for more details.
549    #[error(transparent)]
550    LibraryError(#[from] LibraryError),
551    /// Message group ID differs from the group's group ID.
552    #[error("Message group ID differs from the group's group ID.")]
553    WrongGroupId,
554    /// Message epoch differs from the group's epoch.
555    #[error("Message epoch differs from the group's epoch.")]
556    WrongEpoch,
557    /// The PublicMessage is not a Commit despite the sender begin of type [NewMemberCommit](crate::prelude::Sender::NewMemberCommit).
558    #[error("The PublicMessage is not a Commit despite the sender begin of type NewMemberCommit.")]
559    NotACommit,
560    /// The PublicMessage is not an External Add Proposal despite the sender begin of type [NewMemberProposal](crate::prelude::Sender::NewMemberProposal).
561    #[error("The PublicMessage is not an external Add proposal despite the sender begin of type NewMemberProposal.")]
562    NotAnExternalAddProposal,
563    /// The Commit doesn't have a path despite the sender being of type NewMemberCommit.
564    #[error("The Commit doesn't have a path despite the sender being of type NewMemberCommit.")]
565    NoPath,
566    /// The PublicMessage contains an application message but was not encrypted.
567    #[error("The PublicMessage contains an application message but was not encrypted.")]
568    UnencryptedApplicationMessage,
569    /// Sender is not part of the group.
570    #[error("Sender is not part of the group.")]
571    UnknownMember,
572    /// Membership tag is missing.
573    #[error("Membership tag is missing.")]
574    MissingMembershipTag,
575    /// Membership tag is invalid.
576    #[error("Membership tag is invalid.")]
577    InvalidMembershipTag,
578    /// The confirmation tag is missing.
579    #[error("The confirmation tag is missing.")]
580    MissingConfirmationTag,
581    /// Wrong wire format.
582    #[error("Wrong wire format.")]
583    WrongWireFormat,
584    /// Verifying the signature failed.
585    #[error("Verifying the signature failed.")]
586    InvalidSignature,
587    /// An application message was sent from an external sender.
588    #[error("An application message was sent from an external sender.")]
589    NonMemberApplicationMessage,
590    /// Could not decrypt the message
591    #[error(transparent)]
592    UnableToDecrypt(#[from] MessageDecryptionError),
593    /// The message is from an epoch too far in the past.
594    #[error("The message is from an epoch too far in the past.")]
595    NoPastEpochData,
596    /// The provided external sender is not authorized to send external proposals
597    #[error("The provided external sender is not authorized to send external proposals")]
598    UnauthorizedExternalSender,
599    /// The group doesn't contain external senders extension.
600    #[error("The group doesn't contain external senders extension")]
601    NoExternalSendersExtension,
602    /// The KeyPackage could not be validated.
603    #[error(transparent)]
604    KeyPackageVerifyError(#[from] KeyPackageVerifyError),
605    /// The UpdatePath could not be validated.
606    #[error(transparent)]
607    UpdatePathError(#[from] UpdatePathError),
608    /// Invalid LeafNode signature.
609    #[error("Invalid LeafNode signature.")]
610    InvalidLeafNodeSignature,
611    /// Invalid LeafNode source type
612    #[error("Invalid LeafNode source type")]
613    InvalidLeafNodeSourceType,
614    /// Invalid sender type.
615    #[error("Invalid sender type")]
616    InvalidSenderType,
617    /// The Commit includes update proposals from the committer.
618    #[error("The Commit includes update proposals from the committer.")]
619    CommitterIncludedOwnUpdate,
620    /// The ciphersuite in the KeyPackage of the Add proposal does not match the group context.
621    #[error(
622        "The ciphersuite in the KeyPackage of the Add proposal does not match the group context."
623    )]
624    InvalidAddProposalCiphersuite,
625    /// See [`ExternalCommitValidationError`] for more details.
626    #[error(transparent)]
627    ExternalCommitValidation(#[from] ExternalCommitValidationError),
628    /// See [`InvalidExtensionError`]
629    #[error("Invalid extension")]
630    InvalidExtension(#[from] InvalidExtensionError),
631}
632
633/// Proposal validation error
634#[derive(Error, Debug, PartialEq, Clone)]
635pub enum ProposalValidationError {
636    /// See [`LibraryError`] for more details.
637    #[error(transparent)]
638    LibraryError(#[from] LibraryError),
639    /// The sender could not be matched to a member of the group.
640    #[error("The sender could not be matched to a member of the group.")]
641    UnknownMember,
642    /// Duplicate signature key in proposals and group.
643    #[error("Duplicate signature key in proposals and group.")]
644    DuplicateSignatureKey,
645    /// Duplicate encryption key in proposals and group.
646    #[error("Duplicate encryption key in proposals and group.")]
647    DuplicateEncryptionKey,
648    /// Duplicate init key in proposals.
649    #[error("Duplicate init key in proposals.")]
650    DuplicateInitKey,
651    /// The HPKE init and encryption keys are the same.
652    #[error("The HPKE init and encryption keys are the same.")]
653    InitEncryptionKeyCollision,
654    /// Duplicate remove proposals for the same member.
655    #[error("Duplicate remove proposals for the same member.")]
656    DuplicateMemberRemoval,
657    /// The remove proposal referenced a non-existing member.
658    #[error("The remove proposal referenced a non-existing member.")]
659    UnknownMemberRemoval,
660    /// Found an update from a non-member.
661    #[error("Found an update from a non-member.")]
662    UpdateFromNonMember,
663    /// The Commit includes update proposals from the committer.
664    #[error("The Commit includes update proposals from the committer.")]
665    CommitterIncludedOwnUpdate,
666    /// The capabilities of the add proposal are insufficient for this group.
667    #[error("The capabilities of the add proposal are insufficient for this group.")]
668    InsufficientCapabilities,
669    /// The add proposal's ciphersuite or protocol version do not match the ones in the group context.
670    #[error(
671        "The add proposal's ciphersuite or protocol version do not match the ones in the group context."
672    )]
673    InvalidAddProposalCiphersuiteOrVersion,
674    /// See [`PskError`] for more details.
675    #[error(transparent)]
676    Psk(#[from] PskError),
677    /// The proposal type is not supported by all group members.
678    #[error("The proposal type is not supported by all group members.")]
679    UnsupportedProposalType,
680    /// See [`LeafNodeValidationError`] for more details.
681    #[error(transparent)]
682    LeafNodeValidation(#[from] LeafNodeValidationError),
683    /// Regular Commits may not contain ExternalInit proposals, but one was found
684    #[error("Found ExternalInit proposal in regular commit")]
685    ExternalInitProposalInRegularCommit,
686}
687
688/// External Commit validaton error
689#[derive(Error, Debug, PartialEq, Clone)]
690pub enum ExternalCommitValidationError {
691    /// See [`LibraryError`] for more details.
692    #[error(transparent)]
693    LibraryError(#[from] LibraryError),
694    /// No ExternalInit proposal found.
695    #[error("No ExternalInit proposal found.")]
696    NoExternalInitProposals,
697    /// Multiple ExternalInit proposal found.
698    #[error("Multiple ExternalInit proposal found.")]
699    MultipleExternalInitProposals,
700    /// Found inline Add or Update proposals.
701    #[error("Found inline Add or Update proposals.")]
702    InvalidInlineProposals,
703    /// Found multiple inline Remove proposals.
704    #[error("Found multiple inline Remove proposals.")]
705    MultipleRemoveProposals,
706    /// Remove proposal targets the wrong group member.
707    #[error("Remove proposal targets the wrong group member.")]
708    InvalidRemoveProposal,
709    /// External Commit has to contain a path.
710    #[error("External Commit has to contain a path.")]
711    NoPath,
712    /// External commit contains referenced proposal
713    #[error("Found a referenced proposal in an External Commit.")]
714    ReferencedProposal,
715    /// External committer's leaf node does not support all group context extensions.
716    #[error("External committer's leaf node does not support all group context extensions.")]
717    UnsupportedGroupContextExtensions,
718}
719
720/// Create add proposal error
721#[derive(Error, Debug, PartialEq, Clone)]
722pub enum CreateAddProposalError {
723    /// See [`LibraryError`] for more details.
724    #[error(transparent)]
725    LibraryError(#[from] LibraryError),
726    /// See [`LeafNodeValidationError`] for more details.
727    #[error(transparent)]
728    LeafNodeValidation(#[from] LeafNodeValidationError),
729}
730
731// === Crate errors ===
732
733/// Proposal queue error
734#[derive(Error, Debug, PartialEq, Clone)]
735pub(crate) enum ProposalQueueError {
736    /// See [`LibraryError`] for more details.
737    #[error(transparent)]
738    LibraryError(#[from] LibraryError),
739    /// Not all proposals in the Commit were found locally.
740    #[error("Not all proposals in the Commit were found locally.")]
741    ProposalNotFound,
742    /// Update proposal from external sender.
743    #[error("Update proposal from external sender.")]
744    UpdateFromExternalSender,
745    /// SelfRemove proposal from a non-Member.
746    #[error("SelfRemove proposal from a non-Member.")]
747    SelfRemoveFromNonMember,
748}
749
750/// Errors that can arise when creating a [`ProposalQueue`] from committed
751/// proposals.
752#[derive(Error, Debug, PartialEq, Clone)]
753pub(crate) enum FromCommittedProposalsError {
754    /// See [`LibraryError`] for more details.
755    #[error(transparent)]
756    LibraryError(#[from] LibraryError),
757    /// Not all proposals in the Commit were found locally.
758    #[error("Not all proposals in the Commit were found locally.")]
759    ProposalNotFound,
760    /// The sender of a Commit tried to remove themselves.
761    #[error("The sender of a Commit tried to remove themselves.")]
762    SelfRemoval,
763    /// Commit contains two PSK proposals with the same PSK ID.
764    #[error("Commit contains two PSK proposals the PSK ID {0:?}.")]
765    DuplicatePskId(PreSharedKeyId),
766}
767
768/// Create group context ext proposal error
769#[derive(Error, Debug, PartialEq, Clone)]
770pub enum CreateGroupContextExtProposalError<StorageError> {
771    /// See [`LibraryError`] for more details.
772    #[error(transparent)]
773    LibraryError(#[from] LibraryError),
774    /// See [`KeyPackageExtensionSupportError`] for more details.
775    #[error(transparent)]
776    KeyPackageExtensionSupport(#[from] KeyPackageExtensionSupportError),
777    /// See [`ExtensionError`] for more details.
778    #[error(transparent)]
779    Extension(#[from] ExtensionError),
780    /// See [`LeafNodeValidationError`] for more details.
781    #[error(transparent)]
782    LeafNodeValidation(#[from] LeafNodeValidationError),
783    /// See [`MlsGroupStateError`] for more details.
784    #[error(transparent)]
785    MlsGroupStateError(#[from] MlsGroupStateError),
786    /// See [`CreateCommitError`] for more details.
787    #[error(transparent)]
788    CreateCommitError(#[from] CreateCommitError),
789    /// See [`CommitBuilderStageError`] for more details.
790    #[error(transparent)]
791    CommitBuilderStageError(#[from] CommitBuilderStageError<StorageError>),
792    /// Error writing updated group to storage.
793    #[error("Error writing updated group data to storage.")]
794    StorageError(StorageError),
795    /// Error validating the extensions
796    #[error(transparent)]
797    InvalidExtensionError(#[from] InvalidExtensionError),
798}
799
800/// Error merging a commit.
801#[derive(Error, Debug, PartialEq, Clone)]
802pub enum MergeCommitError<StorageError> {
803    /// See [`LibraryError`] for more details.
804    #[error(transparent)]
805    LibraryError(#[from] LibraryError),
806    /// Error writing updated group to storage.
807    #[error("Error writing updated group data to storage.")]
808    StorageError(StorageError),
809    /// The commit creates a virtual-clients derivation epoch for this emulation
810    /// group, and registering it failed.
811    #[cfg(feature = "virtual-clients-draft")]
812    #[error(transparent)]
813    RegisterVcDerivationEpoch(#[from] crate::group::RegisterVcDerivationEpochError<StorageError>),
814}
815
816#[cfg(feature = "extensions-draft")]
817/// Error validating an AppDataUpdate proposal.
818#[derive(Error, Debug, PartialEq, Clone)]
819pub enum AppDataUpdateValidationError {
820    /// [`AppDataUpdateProposal`](crate::messages::proposals::AppDataUpdateProposal)s
821    /// occur before
822    /// [`GroupContextExtensionsProposal`](crate::messages::proposals::GroupContextExtensionProposal)s.
823    #[error("AppDataUpdate proposals occur before GroupContextExtensions proposals.")]
824    IncorrectOrder,
825    /// Attempted to update the [`AppDataDictionary`](crate::extensions::AppDataDictionary)
826    /// in the
827    /// [`GroupContextExtensionsProposal`](crate::messages::proposals::GroupContextExtensionProposal) directly.
828    #[error("Attempted to update the AppDataDictionary in the GroupContextExtensions proposal directly.")]
829    CannotUpdateDictionaryDirectly,
830    /// More than one [`AppDataUpdate]` proposal per [`ComponentId`] had a Remove operation.
831    ///
832    /// [`ComponentId`]: crate::component::ComponentId
833    #[error("More than one AppDataUpdate proposal per ComponentId had a Remove operation.")]
834    MoreThanOneRemovePerComponentId,
835    /// Proposals for a [`ComponentId`] had both Remove and Update operations.
836    ///
837    /// [`ComponentId`]: crate::component::ComponentId
838    #[error("Proposals for a ComponentId had both Remove and Update operations.")]
839    CombinedRemoveAndUpdateOperations,
840    /// Proposals for a [`ComponentId`] had a Remove for a nonexistent component.
841    ///
842    /// [`ComponentId`]: crate::component::ComponentId
843    #[error("Proposals for a ComponentId had a Remove for a nonexistent component.")]
844    CannotRemoveNonexistentComponent,
845}
846
847/// Error validation a GroupContextExtensions proposal.
848#[derive(Error, Debug, PartialEq, Clone)]
849pub enum GroupContextExtensionsProposalValidationError {
850    /// Commit has more than one GroupContextExtensions proposal.
851    #[error("Commit has more than one GroupContextExtensions proposal.")]
852    TooManyGCEProposals,
853
854    /// See [`LibraryError`] for more details.
855    #[error(transparent)]
856    LibraryError(#[from] LibraryError),
857
858    /// The new extension types in required capabilties contails extensions that are not supported by all group members.
859    #[error(
860        "The new required capabilties contain extension types that are not supported by all group members."
861    )]
862    ExtensionNotSupportedByAllMembers,
863    /// Proposal changes the immutable metadata extension, which is not allowed.
864    #[error("Proposal changes the immutable metadata extension, which is not allowed.")]
865    ChangedImmutableMetadata,
866
867    /// The new extension types in required capabilties contails extensions that are not supported by all group members.
868    #[error(
869        "The new required capabilties contain extension types that are not supported by all group members."
870    )]
871    RequiredExtensionNotSupportedByAllMembers,
872
873    /// An extension in the group context extensions is not listed in the required capabilties'
874    /// extension types.
875    #[error(
876        "An extension in the group context extensions is not listed in the required capabilties' extension types."
877    )]
878    ExtensionNotInRequiredCapabilities,
879
880    /// An extension with a type that is not valid in the group context
881    #[error("Expected valid `Extension` for `GroupContextExtension`, got `{wrong:?}`")]
882    InvalidExtensionTypeError {
883        /// found invalid type
884        wrong: ExtensionType,
885    },
886}