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 identity;
20mod immutable_database;
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};
37use core_crypto_keystore::{entities::StoredCredential, traits::FetchFromDatabase};
38#[cfg(test)]
39pub use core_crypto_macros::{dispotent, durable, idempotent};
40pub(crate) use immutable_database::ImmutableDatabase;
41pub use openmls::{
42 group::{MlsGroup, MlsGroupConfig},
43 prelude::{
44 Ciphersuite as MlsCiphersuite, GroupEpoch, KeyPackageIn, MlsMessageIn, MlsMessageInBody, Node, SignatureScheme,
45 group_info::VerifiableGroupInfo,
46 },
47};
48use wire_e2e_identity::{legacy::device_status::DeviceStatus, pki_env::PkiEnvironment};
49
50pub use crate::{
51 build_metadata::{BUILD_METADATA, BuildMetadata},
52 ephemeral::{HISTORY_CLIENT_ID_PREFIX, HistorySecret},
53 error::{
54 Error, InnermostErrorMessage, KeystoreError, LeafError, OpenMlsError, OpenMlsErrorKind, ProteusError,
55 ProteusErrorKind, RecursiveError, Result, ToRecursiveError,
56 },
57 identity::{WireIdentity, X509Identity},
58 mls::{
59 ExternalSender,
60 cipher_suite::CipherSuite,
61 conversation::{
62 BufferedDecryptedMessage, CommitBundle, ConversationConfiguration, ConversationId, CustomConfiguration,
63 DecryptedMessage, GroupInfoBundle, GroupInfoEncryptionType, GroupInfoPayload, RatchetTreeType, WirePolicy,
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, QualifiedClientId},
72 identifier::ClientIdentifier,
73 user_id::UserId,
74 },
75 },
76 mls_provider::{CryptoProvider, EntropySeed, 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 TransportData(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: CommitBundle) -> Result<()>;
94
95 async fn prepare_for_transport(&self, secret: &HistorySecret) -> Result<TransportData>;
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: CommitBundle) -> crate::Result<()> {
113 Err(Error::MlsTransportNotProvided)
114 }
115
116 async fn prepare_for_transport(&self, _secret: &HistorySecret) -> crate::Result<TransportData> {
117 Err(Error::MlsTransportNotProvided)
118 }
119}
120
121#[derive(Debug)]
126pub struct CoreCrypto {
127 database: Database,
128 pki_environment: RwLock<Option<Arc<PkiEnvironment>>>,
129 mls: RwLock<Option<mls::session::Session>>,
130 #[cfg(feature = "proteus")]
131 proteus: Mutex<Option<proteus::ProteusCentral>>,
132 #[cfg(not(feature = "proteus"))]
133 #[allow(dead_code)]
134 proteus: (),
135}
136
137impl CoreCrypto {
138 pub fn new(database: Database) -> Arc<Self> {
140 Self {
141 database,
142 pki_environment: Default::default(),
143 mls: Default::default(),
144 proteus: Default::default(),
145 }
146 .into()
147 }
148
149 pub async fn set_pki_environment(&self, pki_environment: Option<Arc<PkiEnvironment>>) {
151 *self.pki_environment.write().await = pki_environment.clone();
152 if let Some(mls_session) = self.mls.write().await.as_mut() {
153 mls_session.crypto_provider.set_pki_environment(pki_environment).await;
154 }
155 }
156
157 pub async fn get_pki_environment(&self) -> Option<Arc<PkiEnvironment>> {
159 self.pki_environment.read().await.clone()
160 }
161
162 pub async fn public_key(&self, credential_ref: &CredentialRef) -> Result<Vec<u8>> {
164 self.database
165 .get::<StoredCredential>(&credential_ref.public_key_hash())
166 .await
167 .map_err(KeystoreError::wrap("finding credential"))?
168 .ok_or(mls::credential::credential_ref::Error::CredentialNotFound)
169 .map_err(RecursiveError::mls_credential_ref("retrieving public key"))
170 .map(|stored_credential: StoredCredential| stored_credential.public_key.clone())
171 .map_err(Into::into)
172 }
173
174 pub async fn find_credentials(&self, find_filters: CredentialFindFilters<'_>) -> Result<Vec<CredentialRef>> {
178 CredentialRef::find(&self.database(), find_filters)
179 .await
180 .map_err(RecursiveError::mls_credential_ref("finding credentials with filters"))
181 .map_err(Into::into)
182 }
183
184 pub async fn get_credentials(&self) -> Result<Vec<CredentialRef>> {
186 self.find_credentials(Default::default()).await
187 }
188
189 pub async fn mls_session(&self) -> Result<Session> {
191 if let Some(session) = self.mls.read().await.as_ref() {
192 return Ok(session.clone());
193 }
194 let err = Err(mls::session::Error::MlsNotInitialized);
195 err.map_err(RecursiveError::mls_client("Getting mls session"))?
196 }
197
198 pub fn database(&self) -> ImmutableDatabase {
200 self.database.clone().into()
201 }
202}