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