core_crypto/
lib.rs

1//! Core Crypto is a wrapper on top of OpenMLS aimed to provide an ergonomic API for usage in web
2//! through Web Assembly and in mobile devices through FFI.
3//!
4//! The goal is provide a easier and less verbose API to create, manage and interact with MLS
5//! groups.
6#![doc = include_str!("../../README.md")]
7#![cfg_attr(not(test), deny(missing_docs))]
8#![allow(clippy::single_component_path_imports)]
9
10use async_lock::Mutex;
11#[cfg(test)]
12pub use core_crypto_macros::{dispotent, durable, idempotent};
13use std::sync::Arc;
14
15pub use self::error::*;
16
17#[cfg(test)]
18#[macro_use]
19pub mod test_utils;
20// both imports above have to be defined at the beginning of the crate for rstest to work
21
22mod error;
23
24/// MLS Abstraction
25pub mod mls;
26
27/// re-export [rusty-jwt-tools](https://github.com/wireapp/rusty-jwt-tools) API
28pub mod e2e_identity;
29
30/// Proteus Abstraction
31#[cfg(feature = "proteus")]
32pub mod proteus;
33
34mod ephemeral;
35mod group_store;
36mod obfuscate;
37pub mod transaction_context;
38
39mod build_metadata;
40use crate::prelude::MlsCommitBundle;
41pub use build_metadata::{BUILD_METADATA, BuildMetadata};
42
43pub use core_crypto_keystore::DatabaseKey;
44
45/// Common imports that should be useful for most uses of the crate
46pub mod prelude {
47    pub use openmls::{
48        group::{MlsGroup, MlsGroupConfig},
49        prelude::{
50            Ciphersuite as CiphersuiteName, Credential, GroupEpoch, KeyPackage, KeyPackageIn, KeyPackageRef,
51            MlsMessageIn, Node, group_info::VerifiableGroupInfo,
52        },
53    };
54
55    pub use mls_crypto_provider::{EntropySeed, MlsCryptoProvider, RawEntropySeed};
56
57    pub use crate::{
58        CoreCrypto, MlsTransport,
59        e2e_identity::{
60            E2eiEnrollment,
61            device_status::DeviceStatus,
62            identity::{WireIdentity, X509Identity},
63            types::{E2eiAcmeChallenge, E2eiAcmeDirectory, E2eiNewAcmeAuthz, E2eiNewAcmeOrder},
64        },
65        ephemeral::HistorySecret,
66        error::{CryptoboxMigrationError, Error, KeystoreError, LeafError, MlsError, ProteusError, RecursiveError},
67        mls::{
68            ciphersuite::MlsCiphersuite,
69            config::MlsClientConfiguration,
70            conversation::{
71                ConversationId, MlsConversation,
72                commit::MlsCommitBundle,
73                config::{MlsConversationConfiguration, MlsCustomConfiguration, MlsWirePolicy},
74                conversation_guard::decrypt::{MlsBufferedConversationDecryptMessage, MlsConversationDecryptMessage},
75                group_info::{GroupInfoPayload, MlsGroupInfoBundle, MlsGroupInfoEncryptionType, MlsRatchetTreeType},
76                proposal::MlsProposalBundle,
77                welcome::WelcomeBundle,
78            },
79            credential::{typ::MlsCredentialType, x509::CertificateBundle},
80            proposal::{MlsProposal, MlsProposalRef},
81            session::Session,
82            session::id::ClientId,
83            session::identifier::ClientIdentifier,
84            session::key_package::INITIAL_KEYING_MATERIAL_COUNT,
85            session::*,
86        },
87        obfuscate::Obfuscated,
88        transaction_context::e2e_identity::{E2eiDumpedPkiEnv, conversation_state::E2eiConversationState},
89    };
90}
91
92/// Response from the delivery service
93pub enum MlsTransportResponse {
94    /// The message was accepted by the delivery service
95    Success,
96    /// A client should have consumed all incoming messages before re-trying.
97    Retry,
98    /// The message was rejected by the delivery service and there's no recovery.
99    Abort {
100        /// Why did the delivery service reject the message?
101        reason: String,
102    },
103}
104
105/// Client callbacks to allow communication with the delivery service.
106/// There are two different endpoints, one for messages and one for commit bundles.
107#[cfg_attr(target_family = "wasm", async_trait::async_trait(?Send))]
108#[cfg_attr(not(target_family = "wasm"), async_trait::async_trait)]
109pub trait MlsTransport: std::fmt::Debug + Send + Sync {
110    /// Send a commit bundle to the corresponding endpoint.
111    async fn send_commit_bundle(&self, commit_bundle: MlsCommitBundle) -> Result<MlsTransportResponse>;
112    /// Send a message to the corresponding endpoint.
113    async fn send_message(&self, mls_message: Vec<u8>) -> Result<MlsTransportResponse>;
114}
115
116/// Wrapper superstruct for both [mls::Client] and [proteus::ProteusCentral]
117///
118/// As [std::ops::Deref] is implemented, this struct is automatically dereferred to [mls::Client] apart from `proteus_*` calls
119///
120/// This is cheap to clone as all internal members have `Arc` wrappers or are `Copy`.
121#[derive(Debug, Clone)]
122pub struct CoreCrypto {
123    mls: mls::session::Session,
124    #[cfg(feature = "proteus")]
125    proteus: Arc<Mutex<Option<proteus::ProteusCentral>>>,
126    #[cfg(not(feature = "proteus"))]
127    #[allow(dead_code)]
128    proteus: (),
129}
130
131impl From<mls::session::Session> for CoreCrypto {
132    fn from(mls: mls::session::Session) -> Self {
133        Self {
134            mls,
135            proteus: Default::default(),
136        }
137    }
138}
139
140impl std::ops::Deref for CoreCrypto {
141    type Target = mls::session::Session;
142
143    fn deref(&self) -> &Self::Target {
144        &self.mls
145    }
146}
147
148impl std::ops::DerefMut for CoreCrypto {
149    fn deref_mut(&mut self) -> &mut Self::Target {
150        &mut self.mls
151    }
152}
153
154impl CoreCrypto {
155    /// Allows to extract the MLS Client from the wrapper superstruct
156    #[inline]
157    pub fn take(self) -> mls::session::Session {
158        self.mls
159    }
160}