use crate::mls::conversation::config::MAX_PAST_EPOCHS;
use crate::prelude::{E2eIdentityError, MlsCredentialType};
#[cfg(all(feature = "cryptobox-migrate", target_family = "wasm"))]
use rexie;
#[derive(Debug, thiserror::Error, strum::IntoStaticStr)]
#[cfg_attr(feature = "uniffi", derive(uniffi::Error))]
#[cfg_attr(feature = "uniffi", uniffi(flat_error))]
pub enum CryptoError {
#[error("End to end identity error")]
E2eiError(#[from] E2eIdentityError),
#[error("Couldn't find conversation")]
ConversationNotFound(crate::prelude::ConversationId),
#[error("Conversation already exists")]
ConversationAlreadyExists(crate::prelude::ConversationId),
#[error("Couldn't find client")]
ClientNotFound(crate::prelude::ClientId),
#[error("Couldn't find pending proposal {0}")]
PendingProposalNotFound(crate::mls::proposal::MlsProposalRef),
#[error("Couldn't find pending commit")]
PendingCommitNotFound,
#[error("Malformed or empty identifier found: {0}")]
MalformedIdentifier(&'static str),
#[error("The provided client signature has not been found in the keystore")]
ClientSignatureNotFound,
#[error("The keystore already contains a stored identity. Cannot create a new one!")]
IdentityAlreadyPresent,
#[error(
r#"The externally-generated client ID initialization cannot continue - there's no provisional keypair in-store!
Have you called `CoreCrypto::generate_raw_keypair` ?"#
)]
NoProvisionalIdentityFound,
#[error(
"Somehow CoreCrypto holds more than one MLS identity. Something might've gone very wrong with this client!"
)]
TooManyIdentitiesPresent,
#[error("One of the locks has been poisoned")]
LockPoisonError,
#[error("We have done something terribly wrong and it needs to be fixed")]
ImplementationError,
#[error("Tried to insert an already existing CredentialBundle")]
CredentialBundleConflict,
#[error("The consumer of this library has misused it")]
ConsumerError,
#[error(transparent)]
MlsProviderError(#[from] mls_crypto_provider::MlsProviderError),
#[error(transparent)]
KeyStoreError(#[from] core_crypto_keystore::CryptoKeystoreError),
#[error(transparent)]
MlsError(MlsError),
#[cfg(test)]
#[error(transparent)]
UuidError(#[from] uuid::Error),
#[error(transparent)]
Utf8Error(#[from] std::str::Utf8Error),
#[error(transparent)]
StringUtf8Error(#[from] std::string::FromUtf8Error),
#[error(transparent)]
ParseIntError(#[from] std::num::ParseIntError),
#[error(transparent)]
ConvertIntError(#[from] std::num::TryFromIntError),
#[error(transparent)]
HexDecodeError(#[from] hex::FromHexError),
#[error("Byte array supplied did not have the expected size {0}")]
InvalidByteArrayError(usize),
#[error(transparent)]
IoError(#[from] std::io::Error),
#[error("A supplied reference is not of the expected size: 16")]
InvalidHashReference,
#[error("Decrypted an application message from the wrong epoch")]
DecryptionError,
#[error("Incoming message is from a prior epoch")]
StaleMessage,
#[error("Incoming message is from an epoch too far in the future to buffer.")]
WrongEpoch,
#[error("Incoming message is for a future epoch. We will buffer it until the commit for that epoch arrives")]
BufferedFutureMessage,
#[error(transparent)]
ProteusError(#[from] ProteusError),
#[error(transparent)]
CryptoboxMigrationError(#[from] CryptoboxMigrationError),
#[error("Proteus client hasn't been initialized")]
ProteusNotInitialized,
#[error("CoreCrypto hasn't been built with Proteus support enabled; The feature `{0}` isn't enabled")]
ProteusSupportNotEnabled(String),
#[error("A MLS operation was requested but MLS hasn't been initialized on this instance")]
MlsNotInitialized,
#[error("Decrypted message uses an invalid KeyPackage")]
InvalidKeyPackage,
#[error("Client presented an invalid identity")]
InvalidIdentity,
#[error("MLS Client was not initialized the right way")]
IdentityInitializationError,
#[error("The specified parent group has not been found in the keystore")]
ParentGroupNotFound,
#[error("The epoch in which message was encrypted is older than {MAX_PAST_EPOCHS}")]
MessageEpochTooOld,
#[error("End-to-end identity enrollment has not been done")]
E2eiEnrollmentNotDone,
#[error("A Credential of type {0:?} was not found locally which is very likely an implementation error")]
CredentialNotFound(MlsCredentialType),
#[error("The MLS group is in an invalid state for an unknown reason")]
InternalMlsError,
#[error("We already decrypted this message once")]
DuplicateMessage,
#[cfg(test)]
#[error("This method leaks entities whereas it's not supposed to")]
LeakEntities,
#[cfg(test)]
#[error("This method does not create new entities whereas it's supposed to")]
NoEntityCreated,
#[error("Happens when a client creates a commit, sends it to the DS which accepts it but then client \
clears this pending commit and creates another commit. This is triggered when the client tries to decrypt the original commit.\
This means something is very wrong in the client's code and has to be fixed immediately")]
ClearingPendingCommitError,
#[error("Tried to decrypt a commit created by self which is likely to have been replayed by the DS")]
SelfCommitIgnored,
#[error(
"You tried to join with an external commit but did not merge it yet. We will reapply this message for you when you merge your external commit"
)]
UnmergedPendingGroup,
#[error(transparent)]
X509CertDerError(#[from] x509_cert::der::Error),
#[error(transparent)]
PemError(#[from] pem::PemError),
#[error("Could not find domain name in the certificate")]
DomainNameNotFound,
#[error("The provided domain name and the one found in the certificate don't match")]
DomainNamesDontMatch,
#[error("A trust anchor with the provided domain name already exists in the group's context extensions")]
DuplicateDomainName,
#[error("The certificate chain is invalid or not complete")]
InvalidCertificateChain,
#[error("The update anchors parameters can't be empty")]
EmptyTrustAnchorUpdate,
#[error("The certificate chain is already in the group's context")]
DuplicateCertificateChain,
#[error("Although this Welcome seems valid, the local KeyPackage it references has already been deleted locally. Join this group with an external commit")]
OrphanWelcome,
#[error("The encountered ClientId does not match Wire's definition")]
InvalidClientId,
#[error(transparent)]
JsonError(#[from] serde_json::Error),
#[error("The received commit is deemed stale and is from an older epoch.")]
StaleCommit,
#[error("The received proposal is deemed stale and is from an older epoch.")]
StaleProposal,
#[error("The group lacks an ExternalSender extension whereas it should have at least one")]
MissingExternalSenderExtension,
#[error("Not supported for the moment")]
Unsupported,
#[error("This context has already been finished and can no longer be used.")]
InvalidContext,
}
impl From<MlsError> for CryptoError {
fn from(err: MlsError) -> Self {
match err {
MlsError::MlsAddMembersError(openmls::prelude::AddMembersError::KeyPackageVerifyError(
openmls::key_packages::errors::KeyPackageVerifyError::InvalidLeafNode(
openmls::prelude::LeafNodeValidationError::InvalidCredential(
openmls::credentials::errors::CredentialError::AuthenticationServiceValidationFailure(
openmls_traits::authentication_service::CredentialAuthenticationStatus::Invalid,
),
),
),
)) => Self::InvalidIdentity,
e => Self::MlsError(e),
}
}
}
pub type CryptoResult<T> = Result<T, CryptoError>;
impl CryptoError {
pub fn proteus_error_code(&self) -> Option<u16> {
if let Self::ProteusError(e) = self {
e.error_code()
} else {
None
}
}
}
#[derive(Debug, thiserror::Error, strum::IntoStaticStr)]
pub enum MlsError {
#[error(transparent)]
MlsWelcomeError(#[from] openmls::prelude::WelcomeError<core_crypto_keystore::CryptoKeystoreError>),
#[error(transparent)]
MlsLibraryError(#[from] openmls::error::LibraryError),
#[error(transparent)]
MlsInvalidMessageError(#[from] openmls::prelude::CreateMessageError),
#[error(transparent)]
MlsEmptyInputError(#[from] openmls::prelude::EmptyInputError),
#[error(transparent)]
MlsCredentialError(#[from] openmls::prelude::CredentialError),
#[error(transparent)]
MlsNewGroupError(#[from] openmls::prelude::NewGroupError<core_crypto_keystore::CryptoKeystoreError>),
#[error(transparent)]
MlsAddMembersError(#[from] openmls::prelude::AddMembersError<core_crypto_keystore::CryptoKeystoreError>),
#[error(transparent)]
MlsRemoveMembersError(#[from] openmls::prelude::RemoveMembersError<core_crypto_keystore::CryptoKeystoreError>),
#[error(transparent)]
MlsMessageError(#[from] openmls::prelude::ProcessMessageError),
#[error(transparent)]
MlsKeyPackageBundleNewError(
#[from] openmls::prelude::KeyPackageNewError<core_crypto_keystore::CryptoKeystoreError>,
),
#[error(transparent)]
MlsSelfUpdateError(#[from] openmls::prelude::SelfUpdateError<core_crypto_keystore::CryptoKeystoreError>),
#[error(transparent)]
MlsMlsGroupStateError(#[from] openmls::prelude::MlsGroupStateError),
#[error(transparent)]
ProposeAddMemberError(#[from] openmls::prelude::ProposeAddMemberError),
#[error(transparent)]
ProposeSelfUpdateError(#[from] openmls::prelude::ProposeSelfUpdateError<core_crypto_keystore::CryptoKeystoreError>),
#[error(transparent)]
ProposeRemoveMemberError(#[from] openmls::prelude::ProposeRemoveMemberError),
#[error(transparent)]
MlsCommitToPendingProposalsError(
#[from] openmls::prelude::CommitToPendingProposalsError<core_crypto_keystore::CryptoKeystoreError>,
),
#[error(transparent)]
MlsExportGroupInfoError(#[from] openmls::prelude::ExportGroupInfoError),
#[error(transparent)]
MlsTlsCodecError(#[from] tls_codec::Error),
#[error(transparent)]
MlsKeystoreSerializationError(#[from] serde_json::Error),
#[error(transparent)]
MlsErrorString(#[from] openmls::error::ErrorString),
#[error(transparent)]
MlsExternalCommitError(#[from] openmls::prelude::ExternalCommitError),
#[error(transparent)]
MlsCryptoError(#[from] openmls::prelude::CryptoError),
#[error(transparent)]
MlsExportSecretError(#[from] openmls::prelude::ExportSecretError),
#[error(transparent)]
MlsMergeCommitError(#[from] openmls::prelude::MergeCommitError<core_crypto_keystore::CryptoKeystoreError>),
#[error(transparent)]
MlsKeyPackageValidationError(#[from] openmls::prelude::KeyPackageVerifyError),
#[error(transparent)]
MlsMergePendingCommitError(
#[from] openmls::prelude::MergePendingCommitError<core_crypto_keystore::CryptoKeystoreError>,
),
#[error(transparent)]
MlsEncryptMessageError(#[from] openmls::framing::errors::MlsMessageError),
#[error(transparent)]
MlsDeleteKeyPackageError(
#[from] openmls::key_packages::errors::KeyPackageDeleteError<core_crypto_keystore::CryptoKeystoreError>,
),
#[error(transparent)]
MlsUpdateExtensionsError(
#[from] openmls::prelude::UpdateExtensionsError<core_crypto_keystore::CryptoKeystoreError>,
),
#[error(transparent)]
MlsLeafNodeValidationError(#[from] openmls::prelude::LeafNodeValidationError),
#[error(transparent)]
RatchetTreeError(#[from] openmls::treesync::RatchetTreeError),
#[error(transparent)]
GroupInfoError(#[from] openmls::messages::group_info::GroupInfoError),
}
#[derive(Debug, thiserror::Error, strum::IntoStaticStr)]
pub enum ProteusError {
#[cfg(feature = "proteus")]
#[error(transparent)]
ProteusDecodeError(#[from] proteus_wasm::DecodeError),
#[cfg(feature = "proteus")]
#[error(transparent)]
ProteusEncodeError(#[from] proteus_wasm::EncodeError),
#[cfg(feature = "proteus")]
#[error(transparent)]
ProteusInternalError(#[from] proteus_wasm::error::ProteusError),
#[cfg(feature = "proteus")]
#[error(transparent)]
ProteusSessionError(#[from] proteus_wasm::session::Error<core_crypto_keystore::CryptoKeystoreError>),
}
impl ProteusError {
pub fn error_code(&self) -> Option<u16> {
cfg_if::cfg_if! {
if #[cfg(feature = "proteus")] {
use proteus_traits::{ProteusErrorCode as _, ProteusErrorKind};
let kind = match self {
ProteusError::ProteusDecodeError(e) => e.code(),
ProteusError::ProteusEncodeError(e) => e.code(),
ProteusError::ProteusSessionError(e) => e.code(),
ProteusError::ProteusInternalError(e) => e.code(),
};
(kind != ProteusErrorKind::None).then_some(kind as u16)
} else {
None
}
}
}
}
#[derive(Debug, thiserror::Error, strum::IntoStaticStr)]
pub enum CryptoboxMigrationError {
#[cfg(all(feature = "cryptobox-migrate", target_family = "wasm"))]
#[error(transparent)]
RexieError(rexie::Error),
#[cfg(all(feature = "cryptobox-migrate", target_family = "wasm"))]
#[error(transparent)]
IdbError(idb::Error),
#[cfg(all(feature = "cryptobox-migrate", target_family = "wasm"))]
#[error(transparent)]
JsonParseError(#[from] serde_wasm_bindgen::Error),
#[cfg(all(feature = "cryptobox-migrate", target_family = "wasm"))]
#[error(transparent)]
Base64DecodeError(#[from] base64::DecodeError),
#[error("The targeted value does not possess the targeted key ({0})")]
MissingKeyInValue(String),
#[error("The value cannot be coerced to the {0} type")]
WrongValueType(String),
#[cfg_attr(target_family = "wasm", error("The provided path [{0}] could not be found."))]
#[cfg_attr(
not(target_family = "wasm"),
error("The provided path store [{0}] is either non-existent or has an incorrect shape.")
)]
ProvidedPathDoesNotExist(String),
#[error("The Cryptobox identity at path [{0}] could not be found.")]
IdentityNotFound(String),
}
#[cfg(all(feature = "cryptobox-migrate", target_family = "wasm"))]
impl From<rexie::Error> for CryptoboxMigrationError {
fn from(e: rexie::Error) -> Self {
match e {
rexie::Error::IdbError(e) => Self::IdbError(e),
_ => Self::RexieError(e),
}
}
}