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)]
910use async_lock::Mutex;
11#[cfg(test)]
12pub use core_crypto_macros::{dispotent, durable, idempotent};
13use std::sync::Arc;
1415pub use self::error::*;
1617#[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
2122mod error;
2324/// MLS Abstraction
25pub mod mls;
2627/// re-export [rusty-jwt-tools](https://github.com/wireapp/rusty-jwt-tools) API
28pub mod e2e_identity;
2930/// Proteus Abstraction
31#[cfg(feature = "proteus")]
32pub mod proteus;
3334mod group_store;
35mod obfuscate;
36pub mod transaction_context;
3738mod build_metadata;
39use crate::prelude::MlsCommitBundle;
40pub use build_metadata::{BUILD_METADATA, BuildMetadata};
4142pub use core_crypto_keystore::DatabaseKey;
4344/// Common imports that should be useful for most uses of the crate
45pub mod prelude {
46pub 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 };
5354pub use mls_crypto_provider::{EntropySeed, MlsCryptoProvider, RawEntropySeed};
5556pub 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}
8990/// Response from the delivery service
91pub enum MlsTransportResponse {
92/// The message was accepted by the delivery service
93Success,
94/// A client should have consumed all incoming messages before re-trying.
95Retry,
96/// The message was rejected by the delivery service and there's no recovery.
97Abort {
98/// Why did the delivery service reject the message?
99reason: String,
100 },
101}
102103/// 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.
109async fn send_commit_bundle(&self, commit_bundle: MlsCommitBundle) -> Result<MlsTransportResponse>;
110/// Send a message to the corresponding endpoint.
111async fn send_message(&self, mls_message: Vec<u8>) -> Result<MlsTransportResponse>;
112}
113114/// 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")]
123proteus: Arc<Mutex<Option<proteus::ProteusCentral>>>,
124#[cfg(not(feature = "proteus"))]
125 #[allow(dead_code)]
126proteus: (),
127}
128129impl From<mls::session::Session> for CoreCrypto {
130fn from(mls: mls::session::Session) -> Self {
131Self {
132 mls,
133 proteus: Default::default(),
134 }
135 }
136}
137138impl std::ops::Deref for CoreCrypto {
139type Target = mls::session::Session;
140141fn deref(&self) -> &Self::Target {
142&self.mls
143 }
144}
145146impl std::ops::DerefMut for CoreCrypto {
147fn deref_mut(&mut self) -> &mut Self::Target {
148&mut self.mls
149 }
150}
151152impl CoreCrypto {
153/// Allows to extract the MLS Client from the wrapper superstruct
154#[inline]
155pub fn take(self) -> mls::session::Session {
156self.mls
157 }
158}