1#![doc = include_str!(env!("STRIPPED_README_PATH"))]
7#![cfg_attr(not(test), deny(missing_docs))]
8#![allow(clippy::single_component_path_imports)]
9
10#[cfg(test)]
11#[macro_use]
12pub mod test_utils;
13mod build_metadata;
16mod ephemeral;
17mod error;
18mod group_store;
19mod identity;
20
21pub mod mls;
23mod mls_provider;
24#[cfg(feature = "proteus")]
26pub mod proteus;
27pub mod transaction_context;
28
29use std::sync::Arc;
30
31#[cfg(feature = "proteus")]
32use async_lock::Mutex;
33use async_lock::RwLock;
34pub use core_crypto_keystore::{ConnectionType, Database, DatabaseKey};
35#[cfg(test)]
36pub use core_crypto_macros::{dispotent, durable, idempotent};
37pub use openmls::{
38 group::{MlsGroup, MlsGroupConfig},
39 prelude::{
40 Ciphersuite as MlsCiphersuite, GroupEpoch, KeyPackageIn, MlsMessageIn, Node, SignatureScheme,
41 group_info::VerifiableGroupInfo,
42 },
43};
44use wire_e2e_identity::{legacy::device_status::DeviceStatus, pki_env::PkiEnvironment};
45
46pub use crate::{
47 build_metadata::{BUILD_METADATA, BuildMetadata},
48 ephemeral::{HISTORY_CLIENT_ID_PREFIX, HistorySecret},
49 error::{
50 Error, InnermostErrorMessage, KeystoreError, LeafError, MlsError, MlsErrorKind, ProteusError, ProteusErrorKind,
51 RecursiveError, Result, ToRecursiveError,
52 },
53 identity::{WireIdentity, X509Identity},
54 mls::{
55 ciphersuite::Ciphersuite,
56 conversation::{
57 ConversationId, MlsConversation,
58 commit::MlsCommitBundle,
59 config::{MlsConversationConfiguration, MlsCustomConfiguration, MlsWirePolicy},
60 conversation_guard::decrypt::{MlsBufferedConversationDecryptMessage, MlsConversationDecryptMessage},
61 group_info::{GroupInfoPayload, MlsGroupInfoBundle, MlsGroupInfoEncryptionType, MlsRatchetTreeType},
62 proposal::MlsProposalBundle,
63 },
64 credential::{
65 Credential, CredentialRef, CredentialType, FindFilters as CredentialFindFilters, x509::CertificateBundle,
66 },
67 key_package::{Keypackage, KeypackageRef},
68 proposal::{MlsProposal, MlsProposalRef},
69 session::{
70 EpochObserver, HistoryObserver, Session,
71 id::{ClientId, ClientIdRef},
72 identifier::ClientIdentifier,
73 user_id::UserId,
74 },
75 },
76 mls_provider::{EntropySeed, MlsCryptoProvider, RawEntropySeed, RustCrypto},
77 transaction_context::{
78 e2e_identity::conversation_state::E2eiConversationState, key_package::KEYPACKAGE_DEFAULT_LIFETIME,
79 },
80};
81
82pub enum MlsTransportResponse {
84 Success,
86 Retry,
88 Abort {
90 reason: String,
92 },
93}
94
95#[derive(Debug, derive_more::From, derive_more::Deref, serde::Serialize, serde::Deserialize)]
98pub struct MlsTransportData(pub Vec<u8>);
99
100#[cfg_attr(target_os = "unknown", async_trait::async_trait(?Send))]
103#[cfg_attr(not(target_os = "unknown"), async_trait::async_trait)]
104pub trait MlsTransport: std::fmt::Debug + Send + Sync {
105 async fn send_commit_bundle(&self, commit_bundle: MlsCommitBundle) -> Result<MlsTransportResponse>;
107
108 async fn prepare_for_transport(&self, secret: &HistorySecret) -> Result<MlsTransportData>;
115}
116
117#[derive(Debug, Default)]
120pub struct CoreCryptoTransportNotImplementedProvider();
121
122#[cfg_attr(target_os = "unknown", async_trait::async_trait(?Send))]
123#[cfg_attr(not(target_os = "unknown"), async_trait::async_trait)]
124impl MlsTransport for CoreCryptoTransportNotImplementedProvider {
125 async fn send_commit_bundle(&self, _commit_bundle: MlsCommitBundle) -> crate::Result<MlsTransportResponse> {
126 Err(Error::MlsTransportNotProvided)
127 }
128
129 async fn prepare_for_transport(&self, _secret: &HistorySecret) -> crate::Result<MlsTransportData> {
130 Err(Error::MlsTransportNotProvided)
131 }
132}
133
134#[derive(Debug, Clone)]
141pub struct CoreCrypto {
142 database: Database,
143 pki_environment: Arc<RwLock<Option<PkiEnvironment>>>,
144 mls: Arc<RwLock<Option<mls::session::Session<Database>>>>,
145 #[cfg(feature = "proteus")]
146 proteus: Arc<Mutex<Option<proteus::ProteusCentral>>>,
147 #[cfg(not(feature = "proteus"))]
148 #[allow(dead_code)]
149 proteus: (),
150}
151
152impl CoreCrypto {
153 pub fn new(database: Database) -> Self {
155 Self {
156 database,
157 pki_environment: Default::default(),
158 mls: Default::default(),
159 proteus: Default::default(),
160 }
161 }
162
163 pub async fn set_pki_environment(&self, pki_environment: Option<PkiEnvironment>) -> Result<()> {
165 if let Some(mls_session) = self.mls.write().await.as_mut() {
166 mls_session
167 .crypto_provider
168 .set_pki_environment_provider(pki_environment.as_ref().map(|p| p.mls_pki_env_provider()))
169 .await
170 }
171
172 let mut guard = self.pki_environment.write().await;
173 *guard = pki_environment;
174
175 Ok(())
176 }
177
178 pub async fn get_pki_environment(&self) -> Option<PkiEnvironment> {
180 self.pki_environment.read().await.clone()
181 }
182
183 pub async fn mls_session(&self) -> Result<Session<Database>> {
185 if let Some(session) = self.mls.read().await.as_ref() {
186 return Ok(session.clone());
187 }
188 let err = Err(mls::session::Error::MlsNotInitialized);
189 err.map_err(RecursiveError::mls_client("Getting mls session"))?
190 }
191
192 pub fn database(&self) -> Database {
194 self.database.clone()
195 }
196}