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 group_store;
35mod obfuscate;
36pub mod transaction_context;
37
38mod build_metadata;
39use crate::prelude::MlsCommitBundle;
40pub use build_metadata::{BUILD_METADATA, BuildMetadata};
41
42pub use core_crypto_keystore::DatabaseKey;
43
44/// Common imports that should be useful for most uses of the crate
45pub mod prelude {
46    pub use openmls::{
47        group::{MlsGroup, MlsGroupConfig},
48        prelude::{
49            Ciphersuite as CiphersuiteName, Credential, GroupEpoch, KeyPackage, KeyPackageIn, KeyPackageRef,
50            MlsMessageIn, Node, group_info::VerifiableGroupInfo,
51        },
52    };
53
54    pub use mls_crypto_provider::{EntropySeed, MlsCryptoProvider, RawEntropySeed};
55
56    pub use crate::{
57        CoreCrypto, MlsTransport,
58        e2e_identity::{
59            E2eiEnrollment,
60            device_status::DeviceStatus,
61            identity::{WireIdentity, X509Identity},
62            types::{E2eiAcmeChallenge, E2eiAcmeDirectory, E2eiNewAcmeAuthz, E2eiNewAcmeOrder},
63        },
64        error::{CryptoboxMigrationError, Error, KeystoreError, LeafError, MlsError, ProteusError, RecursiveError},
65        mls::{
66            ciphersuite::MlsCiphersuite,
67            config::MlsClientConfiguration,
68            conversation::{
69                ConversationId, MlsConversation,
70                commit::MlsCommitBundle,
71                config::{MlsConversationConfiguration, MlsCustomConfiguration, MlsWirePolicy},
72                conversation_guard::decrypt::{MlsBufferedConversationDecryptMessage, MlsConversationDecryptMessage},
73                group_info::{GroupInfoPayload, MlsGroupInfoBundle, MlsGroupInfoEncryptionType, MlsRatchetTreeType},
74                proposal::MlsProposalBundle,
75                welcome::WelcomeBundle,
76            },
77            credential::{typ::MlsCredentialType, x509::CertificateBundle},
78            proposal::{MlsProposal, MlsProposalRef},
79            session::Session,
80            session::id::ClientId,
81            session::identifier::ClientIdentifier,
82            session::key_package::INITIAL_KEYING_MATERIAL_COUNT,
83            session::*,
84        },
85        obfuscate::Obfuscated,
86        transaction_context::e2e_identity::{E2eiDumpedPkiEnv, conversation_state::E2eiConversationState},
87    };
88}
89
90/// Response from the delivery service
91pub enum MlsTransportResponse {
92    /// The message was accepted by the delivery service
93    Success,
94    /// A client should have consumed all incoming messages before re-trying.
95    Retry,
96    /// The message was rejected by the delivery service and there's no recovery.
97    Abort {
98        /// Why did the delivery service reject the message?
99        reason: String,
100    },
101}
102
103/// Client callbacks to allow communication with the delivery service.
104/// There are two different endpoints, one for messages and one for commit bundles.
105#[cfg_attr(target_family = "wasm", async_trait::async_trait(?Send))]
106#[cfg_attr(not(target_family = "wasm"), async_trait::async_trait)]
107pub trait MlsTransport: std::fmt::Debug + Send + Sync {
108    /// Send a commit bundle to the corresponding endpoint.
109    async fn send_commit_bundle(&self, commit_bundle: MlsCommitBundle) -> Result<MlsTransportResponse>;
110    /// Send a message to the corresponding endpoint.
111    async fn send_message(&self, mls_message: Vec<u8>) -> Result<MlsTransportResponse>;
112}
113
114/// Wrapper superstruct for both [mls::Client] and [proteus::ProteusCentral]
115///
116/// As [std::ops::Deref] is implemented, this struct is automatically dereferred to [mls::Client] apart from `proteus_*` calls
117///
118/// This is cheap to clone as all internal members have `Arc` wrappers or are `Copy`.
119#[derive(Debug, Clone)]
120pub struct CoreCrypto {
121    mls: mls::session::Session,
122    #[cfg(feature = "proteus")]
123    proteus: Arc<Mutex<Option<proteus::ProteusCentral>>>,
124    #[cfg(not(feature = "proteus"))]
125    #[allow(dead_code)]
126    proteus: (),
127}
128
129impl From<mls::session::Session> for CoreCrypto {
130    fn from(mls: mls::session::Session) -> Self {
131        Self {
132            mls,
133            proteus: Default::default(),
134        }
135    }
136}
137
138impl std::ops::Deref for CoreCrypto {
139    type Target = mls::session::Session;
140
141    fn deref(&self) -> &Self::Target {
142        &self.mls
143    }
144}
145
146impl std::ops::DerefMut for CoreCrypto {
147    fn deref_mut(&mut self) -> &mut Self::Target {
148        &mut self.mls
149    }
150}
151
152impl CoreCrypto {
153    /// Allows to extract the MLS Client from the wrapper superstruct
154    #[inline]
155    pub fn take(self) -> mls::session::Session {
156        self.mls
157    }
158}