1use 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#[derive(Error, Debug, PartialEq, Clone)]
34pub enum WelcomeError<StorageError> {
35 #[error(transparent)]
37 GroupSecrets(#[from] GroupSecretsError),
38 #[error("Private part of `init_key` not found in key store.")]
40 PrivateInitKeyNotFound,
41 #[error(transparent)]
43 LibraryError(#[from] LibraryError),
44 #[error("Ciphersuites in Welcome and key package bundle don't match.")]
46 CiphersuiteMismatch,
47 #[error(transparent)]
49 GroupInfo(#[from] GroupInfoError),
50 #[error("No joiner secret found in the Welcome message.")]
52 JoinerSecretNotFound,
53 #[error("No ratchet tree available to build initial tree after receiving a Welcome message.")]
55 MissingRatchetTree,
56 #[error("The computed confirmation tag does not match the expected one.")]
58 ConfirmationTagMismatch,
59 #[error("The signature on the GroupInfo is not valid.")]
61 InvalidGroupInfoSignature,
62 #[error("We don't support the version of the group we are trying to join.")]
64 UnsupportedMlsVersion,
65 #[error("We don't support all capabilities of the group.")]
67 UnsupportedCapability,
68 #[error("Ciphersuite {0:?} of the group we are trying to join is not supported by the crypto provider.")]
70 UnsupportedCiphersuite(Ciphersuite),
71 #[error("Sender not found in tree.")]
73 UnknownSender,
74 #[error("Not a Welcome message.")]
76 NotAWelcomeMessage,
77 #[error("Malformed Welcome message.")]
79 MalformedWelcomeMessage,
80 #[error("Could not decrypt the Welcome message.")]
82 UnableToDecrypt,
83 #[error("Unsupported extensions found in the GroupContext or KeyPackage of another member.")]
85 UnsupportedExtensions,
86 #[error(transparent)]
88 Psk(#[from] PskError),
89 #[error("No matching encryption key was found in the key store.")]
91 NoMatchingEncryptionKey,
92 #[error("No matching key package was found in the key store.")]
94 NoMatchingKeyPackage,
95 #[error(transparent)]
97 PublicTreeError(#[from] PublicTreeError),
98 #[error(transparent)]
101 PublicGroupError(#[from] CreationFromExternalError<StorageError>),
102 #[error(transparent)]
104 LeafNodeValidation(#[from] LeafNodeValidationError),
105 #[error("An error occurred when querying storage")]
107 StorageError(StorageError),
108 #[error("A group with this [`GroupId`] already exists.")]
110 GroupAlreadyExists,
111 #[cfg(feature = "virtual-clients-draft")]
114 #[error(transparent)]
115 VirtualClientsError(#[from] crate::components::vc_derivation_info::VirtualClientsError),
116 #[error(transparent)]
118 KeySchedule(#[from] KeyScheduleError),
119}
120
121#[derive(Error, Debug, PartialEq, Clone)]
123pub enum ExternalCommitError<StorageError> {
124 #[error(transparent)]
126 LibraryError(#[from] LibraryError),
127 #[error("No ratchet tree available to build initial tree.")]
129 MissingRatchetTree,
130 #[error("No external_pub extension available to join group by external commit.")]
132 MissingExternalPub,
133 #[error("Ciphersuite {0:?} of the group we are trying to join is not supported by the crypto provider.")]
135 UnsupportedCiphersuite(Ciphersuite),
136 #[error("Sender not found in tree.")]
138 UnknownSender,
139 #[error("The signature over the given group info is invalid.")]
141 InvalidGroupInfoSignature,
142 #[error("Error creating external commit.")]
144 CommitError(#[from] CreateCommitError),
145 #[error(transparent)]
148 PublicGroupError(#[from] CreationFromExternalError<StorageError>),
149 #[error("Credential is missing from external commit.")]
151 MissingCredential,
152 #[error("An error occurred when writing group to storage.")]
154 StorageError(StorageError),
155}
156
157impl<StorageError> From<ExternalCommitBuilderError<StorageError>>
158 for ExternalCommitError<StorageError>
159{
160 fn from(error: ExternalCommitBuilderError<StorageError>) -> Self {
161 match error {
162 ExternalCommitBuilderError::LibraryError(library_error) => {
163 ExternalCommitError::LibraryError(library_error)
164 }
165 ExternalCommitBuilderError::MissingRatchetTree => {
166 ExternalCommitError::MissingRatchetTree
167 }
168 ExternalCommitBuilderError::MissingExternalPub => {
169 ExternalCommitError::MissingExternalPub
170 }
171 ExternalCommitBuilderError::UnsupportedCiphersuite(ciphersuite) => {
172 ExternalCommitError::UnsupportedCiphersuite(ciphersuite)
173 }
174 ExternalCommitBuilderError::PublicGroupError(creation_from_external_error) => {
175 ExternalCommitError::PublicGroupError(creation_from_external_error)
176 }
177 ExternalCommitBuilderError::StorageError(error) => {
178 ExternalCommitError::StorageError(error)
179 }
180 ExternalCommitBuilderError::InvalidProposal(e) => {
183 log::error!("Error validating proposal in external commit: {e}");
184 ExternalCommitError::LibraryError(LibraryError::custom(
185 "Error creating external commit",
186 ))
187 }
188 }
189 }
190}
191
192#[cfg(feature = "virtual-clients-draft")]
198#[derive(Error, Debug)]
199pub enum VcExternalCommitJoinError<StorageError> {
200 #[error(transparent)]
202 LibraryError(#[from] LibraryError),
203 #[error("No ratchet tree available to build the prior-epoch public group.")]
205 MissingRatchetTree,
206 #[error(transparent)]
208 PublicGroupError(#[from] CreationFromExternalError<StorageError>),
209 #[error(transparent)]
211 ProcessMessageError(#[from] ProcessMessageError<StorageError>),
212 #[error(transparent)]
214 StageCommitError(#[from] StageCommitError),
215 #[error(transparent)]
217 MergeCommitError(#[from] MergeCommitError<StorageError>),
218 #[error("The message is not an external commit.")]
221 NotAnExternalCommit,
222 #[error("The external commit carries no virtual-clients derivation info.")]
225 MissingDerivationInfo,
226 #[error("The external commit references a different emulation epoch.")]
229 EpochIdMismatch,
230 #[error(transparent)]
232 VirtualClientsError(#[from] crate::components::vc_derivation_info::VirtualClientsError),
233 #[error("An error occurred when writing the group to storage.")]
235 StorageError(StorageError),
236}
237
238#[cfg(feature = "virtual-clients-draft")]
244#[derive(Error, Debug)]
245pub enum VcGroupCreationJoinError<StorageError> {
246 #[error(transparent)]
248 LibraryError(#[from] LibraryError),
249 #[error("No ratchet tree available to build the created group's public tree.")]
251 MissingRatchetTree,
252 #[error(transparent)]
255 PublicGroupError(#[from] CreationFromExternalError<StorageError>),
256 #[error("The ratchet tree does not consist of exactly the creator's leaf.")]
258 NotASingleLeafTree,
259 #[error("The creator leaf carries no virtual-clients derivation info.")]
261 MissingDerivationInfo,
262 #[error("The creator leaf references a different emulation epoch.")]
265 EpochIdMismatch,
266 #[error("The creator leaf is not key_package-sourced.")]
269 CreatorLeafNotKeyPackageSourced,
270 #[error("The derived leaf key material does not match the creator leaf.")]
273 LeafKeyMismatch,
274 #[error("The GroupInfo could not be verified against the reconstructed epoch state.")]
277 ConfirmationTagMismatch,
278 #[error(transparent)]
280 VirtualClientsError(#[from] crate::components::vc_derivation_info::VirtualClientsError),
281 #[error("An error occurred when writing the group to storage.")]
283 StorageError(StorageError),
284}
285
286impl<StorageError> From<ExternalCommitBuilderFinalizeError<StorageError>>
287 for ExternalCommitError<StorageError>
288{
289 fn from(error: ExternalCommitBuilderFinalizeError<StorageError>) -> Self {
290 match error {
291 ExternalCommitBuilderFinalizeError::LibraryError(library_error) => {
292 ExternalCommitError::LibraryError(library_error)
293 }
294 ExternalCommitBuilderFinalizeError::StorageError(error) => {
295 ExternalCommitError::StorageError(error)
296 }
297 ExternalCommitBuilderFinalizeError::MergeCommitError(e) => {
298 log::error!("Error merging external commit: {e}");
299 ExternalCommitError::LibraryError(LibraryError::custom(
302 "Error merging external commit",
303 ))
304 }
305 }
306 }
307}
308
309#[derive(Error, Debug, PartialEq, Clone)]
311pub enum StageCommitError {
312 #[cfg(feature = "virtual-clients-draft")]
314 #[error(transparent)]
315 VirtualClientsError(#[from] crate::components::vc_derivation_info::VirtualClientsError),
316 #[error(transparent)]
318 LibraryError(#[from] LibraryError),
319 #[error("The epoch of the group context and PublicMessage didn't match.")]
321 EpochMismatch,
322 #[error("The Commit was created by this client but does not match the pending commit.")]
324 OwnCommitMismatch,
325 #[error("stage_commit was called with an PublicMessage that is not a Commit.")]
327 WrongPlaintextContentType,
328 #[error("Unable to verify the leaf node signature.")]
330 PathLeafNodeVerificationFailure,
331 #[error("Unable to determine commit path.")]
333 RequiredPathNotFound,
334 #[error("The confirmation Tag is missing.")]
336 ConfirmationTagMissing,
337 #[error("The confirmation tag is invalid.")]
339 ConfirmationTagMismatch,
340 #[error("The committer can't remove themselves.")]
342 AttemptedSelfRemoval,
343 #[error("The proposal queue is missing a proposal for the commit.")]
345 MissingProposal,
346 #[error("Missing own key to apply proposal.")]
348 OwnKeyNotFound,
349 #[error("External Committer used the wrong index.")]
351 InconsistentSenderIndex,
352 #[error("The sender is of type external, which is not valid.")]
354 SenderTypeExternal,
355 #[error("The sender is of type NewMemberProposal, which is not valid.")]
357 SenderTypeNewMemberProposal,
358 #[error("Too many new members: the tree is full.")]
360 TooManyNewMembers,
361 #[error(transparent)]
363 ProposalValidationError(#[from] ProposalValidationError),
364 #[error(transparent)]
366 PskError(#[from] PskError),
367 #[error(transparent)]
369 ExternalCommitValidation(#[from] ExternalCommitValidationError),
370 #[error(transparent)]
372 UpdatePathError(#[from] ApplyUpdatePathError),
373 #[error("Missing decryption key.")]
375 MissingDecryptionKey,
376 #[error(transparent)]
378 VerifiedUpdatePathError(#[from] UpdatePathError),
379 #[error(transparent)]
381 GroupContextExtensionsProposalValidationError(
382 #[from] GroupContextExtensionsProposalValidationError,
383 ),
384 #[cfg(feature = "extensions-draft")]
385 #[error(transparent)]
387 AppDataUpdateValidationError(#[from] AppDataUpdateValidationError),
388 #[error(transparent)]
390 LeafNodeValidation(#[from] LeafNodeValidationError),
391 #[cfg(feature = "extensions-draft")]
393 #[error(transparent)]
394 ApplyAppDataUpdateError(#[from] ApplyAppDataUpdateError),
395 #[error("Duplicate PSK proposal with PSK ID {0:?}.")]
397 DuplicatePskId(PreSharedKeyId),
398}
399
400#[derive(Error, Debug, PartialEq, Clone)]
402pub enum CreateCommitError {
403 #[error(transparent)]
405 LibraryError(#[from] LibraryError),
406 #[cfg(feature = "virtual-clients-draft")]
408 #[error(transparent)]
409 VirtualClientsError(#[from] crate::components::vc_derivation_info::VirtualClientsError),
410 #[error("Missing own key to apply proposal.")]
412 OwnKeyNotFound,
413 #[error("The Commit tried to remove self from the group. This is not possible.")]
415 CannotRemoveSelf,
416 #[error("The proposal queue is missing a proposal for the commit.")]
418 MissingProposal,
419 #[error("A proposal has the wrong sender type.")]
421 WrongProposalSenderType,
422 #[error(transparent)]
424 PskError(#[from] PskError),
425 #[error(transparent)]
427 ProposalValidationError(#[from] ProposalValidationError),
428 #[error(transparent)]
430 SignatureError(#[from] SignatureError),
431 #[error("Credential is missing from external commit.")]
433 MissingCredential,
434 #[error(transparent)]
436 PublicTreeError(#[from] PublicTreeError),
437 #[error(transparent)]
439 InvalidExtensionError(#[from] InvalidExtensionError),
440 #[cfg(feature = "extensions-draft")]
441 #[error(transparent)]
443 AppDataUpdateValidationError(#[from] AppDataUpdateValidationError),
444 #[error(transparent)]
446 GroupContextExtensionsProposalValidationError(
447 #[from] GroupContextExtensionsProposalValidationError,
448 ),
449 #[error(transparent)]
451 TreeSyncAddLeaf(#[from] TreeSyncAddLeaf),
452 #[error("Invalid LeafNodeParameters. CredentialWithKey can't be set with new signer.")]
454 InvalidLeafNodeParameters,
455 #[error("Invalid external commit.")]
457 InvalidExternalCommit(#[from] ExternalCommitValidationError),
458 #[cfg(feature = "extensions-draft")]
460 #[error(transparent)]
461 ApplyAppDataUpdateError(#[from] ApplyAppDataUpdateError),
462 #[error(transparent)]
464 LeafNodeValidation(#[from] LeafNodeValidationError),
465}
466
467#[derive(Error, Debug, PartialEq, Clone)]
469pub enum CommitBuilderStageError<StorageError> {
470 #[error(transparent)]
472 LibraryError(#[from] LibraryError),
473 #[error("Error interacting with storage.")]
475 KeyStoreError(StorageError),
476}
477
478#[derive(Error, Debug, PartialEq, Clone)]
480pub enum ExternalCommitBuilderFinalizeError<StorageError> {
481 #[error(transparent)]
483 LibraryError(#[from] LibraryError),
484 #[error("Error interacting with storage.")]
486 StorageError(StorageError),
487 #[error("Error merging external commit.")]
489 MergeCommitError(#[from] MergePendingCommitError<StorageError>),
490}
491
492#[derive(Error, Debug, PartialEq, Clone)]
494pub enum ValidationError {
495 #[error(transparent)]
497 LibraryError(#[from] LibraryError),
498 #[error("Message group ID differs from the group's group ID.")]
500 WrongGroupId,
501 #[error("Message epoch differs from the group's epoch.")]
503 WrongEpoch,
504 #[error("The PublicMessage is not a Commit despite the sender begin of type NewMemberCommit.")]
506 NotACommit,
507 #[error("The PublicMessage is not an external Add proposal despite the sender begin of type NewMemberProposal.")]
509 NotAnExternalAddProposal,
510 #[error("The Commit doesn't have a path despite the sender being of type NewMemberCommit.")]
512 NoPath,
513 #[error("The PublicMessage contains an application message but was not encrypted.")]
515 UnencryptedApplicationMessage,
516 #[error("Sender is not part of the group.")]
518 UnknownMember,
519 #[error("Membership tag is missing.")]
521 MissingMembershipTag,
522 #[error("Membership tag is invalid.")]
524 InvalidMembershipTag,
525 #[error("The confirmation tag is missing.")]
527 MissingConfirmationTag,
528 #[error("Wrong wire format.")]
530 WrongWireFormat,
531 #[error("Verifying the signature failed.")]
533 InvalidSignature,
534 #[error("An application message was sent from an external sender.")]
536 NonMemberApplicationMessage,
537 #[error(transparent)]
539 UnableToDecrypt(#[from] MessageDecryptionError),
540 #[error("The message is from an epoch too far in the past.")]
542 NoPastEpochData,
543 #[error("The provided external sender is not authorized to send external proposals")]
545 UnauthorizedExternalSender,
546 #[error("The group doesn't contain external senders extension")]
548 NoExternalSendersExtension,
549 #[error(transparent)]
551 KeyPackageVerifyError(#[from] KeyPackageVerifyError),
552 #[error(transparent)]
554 UpdatePathError(#[from] UpdatePathError),
555 #[error("Invalid LeafNode signature.")]
557 InvalidLeafNodeSignature,
558 #[error("Invalid LeafNode source type")]
560 InvalidLeafNodeSourceType,
561 #[error("Invalid sender type")]
563 InvalidSenderType,
564 #[error("The Commit includes update proposals from the committer.")]
566 CommitterIncludedOwnUpdate,
567 #[error(
569 "The ciphersuite in the KeyPackage of the Add proposal does not match the group context."
570 )]
571 InvalidAddProposalCiphersuite,
572 #[error(transparent)]
574 ExternalCommitValidation(#[from] ExternalCommitValidationError),
575 #[error("Invalid extension")]
577 InvalidExtension(#[from] InvalidExtensionError),
578}
579
580#[derive(Error, Debug, PartialEq, Clone)]
582pub enum ProposalValidationError {
583 #[error(transparent)]
585 LibraryError(#[from] LibraryError),
586 #[error("The sender could not be matched to a member of the group.")]
588 UnknownMember,
589 #[error("Duplicate signature key in proposals and group.")]
591 DuplicateSignatureKey,
592 #[error("Duplicate encryption key in proposals and group.")]
594 DuplicateEncryptionKey,
595 #[error("Duplicate init key in proposals.")]
597 DuplicateInitKey,
598 #[error("The HPKE init and encryption keys are the same.")]
600 InitEncryptionKeyCollision,
601 #[error("Duplicate remove proposals for the same member.")]
603 DuplicateMemberRemoval,
604 #[error("The remove proposal referenced a non-existing member.")]
606 UnknownMemberRemoval,
607 #[error("Found an update from a non-member.")]
609 UpdateFromNonMember,
610 #[error("The Commit includes update proposals from the committer.")]
612 CommitterIncludedOwnUpdate,
613 #[error("The capabilities of the add proposal are insufficient for this group.")]
615 InsufficientCapabilities,
616 #[error(
618 "The add proposal's ciphersuite or protocol version do not match the ones in the group context."
619 )]
620 InvalidAddProposalCiphersuiteOrVersion,
621 #[error(transparent)]
623 Psk(#[from] PskError),
624 #[error("The proposal type is not supported by all group members.")]
626 UnsupportedProposalType,
627 #[error(transparent)]
629 LeafNodeValidation(#[from] LeafNodeValidationError),
630 #[error("Found ExternalInit proposal in regular commit")]
632 ExternalInitProposalInRegularCommit,
633}
634
635#[derive(Error, Debug, PartialEq, Clone)]
637pub enum ExternalCommitValidationError {
638 #[error(transparent)]
640 LibraryError(#[from] LibraryError),
641 #[error("No ExternalInit proposal found.")]
643 NoExternalInitProposals,
644 #[error("Multiple ExternalInit proposal found.")]
646 MultipleExternalInitProposals,
647 #[error("Found inline Add or Update proposals.")]
649 InvalidInlineProposals,
650 #[error("Found multiple inline Remove proposals.")]
652 MultipleRemoveProposals,
653 #[error("Remove proposal targets the wrong group member.")]
655 InvalidRemoveProposal,
656 #[error("External Commit has to contain a path.")]
658 NoPath,
659 #[error("Found a referenced proposal in an External Commit.")]
661 ReferencedProposal,
662 #[error("External committer's leaf node does not support all group context extensions.")]
664 UnsupportedGroupContextExtensions,
665}
666
667#[derive(Error, Debug, PartialEq, Clone)]
669pub enum CreateAddProposalError {
670 #[error(transparent)]
672 LibraryError(#[from] LibraryError),
673 #[error(transparent)]
675 LeafNodeValidation(#[from] LeafNodeValidationError),
676}
677
678#[derive(Error, Debug, PartialEq, Clone)]
682pub(crate) enum ProposalQueueError {
683 #[error(transparent)]
685 LibraryError(#[from] LibraryError),
686 #[error("Not all proposals in the Commit were found locally.")]
688 ProposalNotFound,
689 #[error("Update proposal from external sender.")]
691 UpdateFromExternalSender,
692 #[error("SelfRemove proposal from a non-Member.")]
694 SelfRemoveFromNonMember,
695}
696
697#[derive(Error, Debug, PartialEq, Clone)]
700pub(crate) enum FromCommittedProposalsError {
701 #[error(transparent)]
703 LibraryError(#[from] LibraryError),
704 #[error("Not all proposals in the Commit were found locally.")]
706 ProposalNotFound,
707 #[error("The sender of a Commit tried to remove themselves.")]
709 SelfRemoval,
710 #[error("Commit contains two PSK proposals the PSK ID {0:?}.")]
712 DuplicatePskId(PreSharedKeyId),
713}
714
715#[derive(Error, Debug, PartialEq, Clone)]
717pub enum CreateGroupContextExtProposalError<StorageError> {
718 #[error(transparent)]
720 LibraryError(#[from] LibraryError),
721 #[error(transparent)]
723 KeyPackageExtensionSupport(#[from] KeyPackageExtensionSupportError),
724 #[error(transparent)]
726 Extension(#[from] ExtensionError),
727 #[error(transparent)]
729 LeafNodeValidation(#[from] LeafNodeValidationError),
730 #[error(transparent)]
732 MlsGroupStateError(#[from] MlsGroupStateError),
733 #[error(transparent)]
735 CreateCommitError(#[from] CreateCommitError),
736 #[error(transparent)]
738 CommitBuilderStageError(#[from] CommitBuilderStageError<StorageError>),
739 #[error("Error writing updated group data to storage.")]
741 StorageError(StorageError),
742 #[error(transparent)]
744 InvalidExtensionError(#[from] InvalidExtensionError),
745}
746
747#[derive(Error, Debug, PartialEq, Clone)]
749pub enum MergeCommitError<StorageError> {
750 #[error(transparent)]
752 LibraryError(#[from] LibraryError),
753 #[error("Error writing updated group data to storage.")]
755 StorageError(StorageError),
756}
757
758#[cfg(feature = "extensions-draft")]
759#[derive(Error, Debug, PartialEq, Clone)]
761pub enum AppDataUpdateValidationError {
762 #[error("AppDataUpdate proposals occur before GroupContextExtensions proposals.")]
766 IncorrectOrder,
767 #[error("Attempted to update the AppDataDictionary in the GroupContextExtensions proposal directly.")]
771 CannotUpdateDictionaryDirectly,
772 #[error("More than one AppDataUpdate proposal per ComponentId had a Remove operation.")]
776 MoreThanOneRemovePerComponentId,
777 #[error("Proposals for a ComponentId had both Remove and Update operations.")]
781 CombinedRemoveAndUpdateOperations,
782 #[error("Proposals for a ComponentId had a Remove for a nonexistent component.")]
786 CannotRemoveNonexistentComponent,
787}
788
789#[derive(Error, Debug, PartialEq, Clone)]
791pub enum GroupContextExtensionsProposalValidationError {
792 #[error("Commit has more than one GroupContextExtensions proposal.")]
794 TooManyGCEProposals,
795
796 #[error(transparent)]
798 LibraryError(#[from] LibraryError),
799
800 #[error(
802 "The new required capabilties contain extension types that are not supported by all group members."
803 )]
804 ExtensionNotSupportedByAllMembers,
805 #[error("Proposal changes the immutable metadata extension, which is not allowed.")]
807 ChangedImmutableMetadata,
808
809 #[error(
811 "The new required capabilties contain extension types that are not supported by all group members."
812 )]
813 RequiredExtensionNotSupportedByAllMembers,
814
815 #[error(
818 "An extension in the group context extensions is not listed in the required capabilties' extension types."
819 )]
820 ExtensionNotInRequiredCapabilities,
821
822 #[error("Expected valid `Extension` for `GroupContextExtension`, got `{wrong:?}`")]
824 InvalidExtensionTypeError {
825 wrong: ExtensionType,
827 },
828}