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 bytes_wrapper;
17mod ephemeral;
18mod error;
19mod group_store;
20mod identity;
21
22pub mod mls;
24mod mls_provider;
25#[cfg(feature = "proteus")]
27pub mod proteus;
28pub mod transaction_context;
29
30use std::sync::Arc;
31
32#[cfg(feature = "proteus")]
33use async_lock::Mutex;
34use async_lock::RwLock;
35pub(crate) use bytes_wrapper::bytes_wrapper;
36pub use core_crypto_keystore::{ConnectionType, Database, DatabaseKey};
37#[cfg(test)]
38pub use core_crypto_macros::{dispotent, durable, idempotent};
39pub use openmls::{
40 group::{MlsGroup, MlsGroupConfig},
41 prelude::{
42 Ciphersuite as MlsCiphersuite, GroupEpoch, KeyPackageIn, MlsMessageIn, MlsMessageInBody, Node, SignatureScheme,
43 group_info::VerifiableGroupInfo,
44 },
45};
46use wire_e2e_identity::{legacy::device_status::DeviceStatus, pki_env::PkiEnvironment};
47
48pub use crate::{
49 build_metadata::{BUILD_METADATA, BuildMetadata},
50 ephemeral::{HISTORY_CLIENT_ID_PREFIX, HistorySecret},
51 error::{
52 Error, InnermostErrorMessage, KeystoreError, LeafError, MlsError, MlsErrorKind, ProteusError, ProteusErrorKind,
53 RecursiveError, Result, ToRecursiveError,
54 },
55 identity::{WireIdentity, X509Identity},
56 mls::{
57 ciphersuite::CipherSuite,
58 conversation::{
59 ConversationId, MlsConversation,
60 commit::MlsCommitBundle,
61 config::{MlsConversationConfiguration, MlsCustomConfiguration, MlsWirePolicy},
62 conversation_guard::decrypt::{MlsBufferedDecryptMessage, MlsDecryptMessage},
63 group_info::{GroupInfoPayload, MlsGroupInfoBundle, MlsGroupInfoEncryptionType, MlsRatchetTreeType},
64 },
65 credential::{
66 Credential, CredentialRef, CredentialType, FindFilters as CredentialFindFilters, x509::CertificateBundle,
67 },
68 key_package::{Keypackage, KeypackageRef},
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
82#[derive(Debug, derive_more::From, derive_more::Deref, serde::Serialize, serde::Deserialize)]
85pub struct MlsTransportData(pub Vec<u8>);
86
87#[cfg_attr(target_os = "unknown", async_trait::async_trait(?Send))]
90#[cfg_attr(not(target_os = "unknown"), async_trait::async_trait)]
91pub trait MlsTransport: std::fmt::Debug + Send + Sync {
92 async fn send_commit_bundle(&self, commit_bundle: MlsCommitBundle) -> Result<()>;
94
95 async fn prepare_for_transport(&self, secret: &HistorySecret) -> Result<MlsTransportData>;
102}
103
104#[derive(Debug, Default)]
107pub struct CoreCryptoTransportNotImplementedProvider();
108
109#[cfg_attr(target_os = "unknown", async_trait::async_trait(?Send))]
110#[cfg_attr(not(target_os = "unknown"), async_trait::async_trait)]
111impl MlsTransport for CoreCryptoTransportNotImplementedProvider {
112 async fn send_commit_bundle(&self, _commit_bundle: MlsCommitBundle) -> crate::Result<()> {
113 Err(Error::MlsTransportNotProvided)
114 }
115
116 async fn prepare_for_transport(&self, _secret: &HistorySecret) -> crate::Result<MlsTransportData> {
117 Err(Error::MlsTransportNotProvided)
118 }
119}
120
121#[derive(Debug, Clone)]
128pub struct CoreCrypto {
129 database: Database,
130 pki_environment: Arc<RwLock<Option<PkiEnvironment>>>,
131 mls: Arc<RwLock<Option<mls::session::Session<Database>>>>,
132 #[cfg(feature = "proteus")]
133 proteus: Arc<Mutex<Option<proteus::ProteusCentral>>>,
134 #[cfg(not(feature = "proteus"))]
135 #[allow(dead_code)]
136 proteus: (),
137}
138
139impl CoreCrypto {
140 pub fn new(database: Database) -> Self {
142 Self {
143 database,
144 pki_environment: Default::default(),
145 mls: Default::default(),
146 proteus: Default::default(),
147 }
148 }
149
150 pub async fn set_pki_environment(&self, pki_environment: Option<PkiEnvironment>) -> Result<()> {
152 if let Some(mls_session) = self.mls.write().await.as_mut() {
153 mls_session
154 .crypto_provider
155 .set_pki_environment_provider(pki_environment.as_ref().map(|p| p.mls_pki_env_provider()))
156 .await
157 }
158
159 let mut guard = self.pki_environment.write().await;
160 *guard = pki_environment;
161
162 Ok(())
163 }
164
165 pub async fn get_pki_environment(&self) -> Option<PkiEnvironment> {
167 self.pki_environment.read().await.clone()
168 }
169
170 pub async fn mls_session(&self) -> Result<Session<Database>> {
172 if let Some(session) = self.mls.read().await.as_ref() {
173 return Ok(session.clone());
174 }
175 let err = Err(mls::session::Error::MlsNotInitialized);
176 err.map_err(RecursiveError::mls_client("Getting mls session"))?
177 }
178
179 pub fn database(&self) -> Database {
181 self.database.clone()
182 }
183}