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