core_crypto_ffi/core_crypto_context/
mls.rs

1use core_crypto::{
2    RecursiveError,
3    mls::conversation::Conversation as _,
4    prelude::{ClientIdentifier, KeyPackageIn, KeyPackageRef, MlsConversationConfiguration, VerifiableGroupInfo},
5    transaction_context::Error as TransactionError,
6};
7use tls_codec::{Deserialize as _, Serialize as _};
8#[cfg(target_family = "wasm")]
9use wasm_bindgen::prelude::*;
10
11use crate::{
12    Ciphersuite, Ciphersuites, ClientId, ConversationConfiguration, ConversationId, CoreCryptoContext, CoreCryptoError,
13    CoreCryptoResult, CredentialType, CustomConfiguration, DecryptedMessage, NewCrlDistributionPoints, WelcomeBundle,
14    conversation_id_vec,
15};
16
17#[cfg(not(target_family = "wasm"))]
18type KeyPackages = Vec<Vec<u8>>;
19
20#[cfg(target_family = "wasm")]
21type KeyPackages = super::array_of_byte_array::ArrayOfByteArray;
22
23#[cfg_attr(target_family = "wasm", wasm_bindgen)]
24#[cfg_attr(not(target_family = "wasm"), uniffi::export)]
25impl CoreCryptoContext {
26    /// See [core_crypto::transaction_context::TransactionContext::mls_init]
27    pub async fn mls_init(
28        &self,
29        client_id: ClientId,
30        ciphersuites: Ciphersuites,
31        nb_key_package: Option<u32>,
32    ) -> CoreCryptoResult<()> {
33        let nb_key_package = nb_key_package
34            .map(usize::try_from)
35            .transpose()
36            .map_err(CoreCryptoError::generic())?;
37        self.inner
38            .mls_init(
39                ClientIdentifier::Basic(client_id.0),
40                (&ciphersuites).into(),
41                nb_key_package,
42            )
43            .await?;
44        Ok(())
45    }
46
47    /// See [core_crypto::transaction_context::TransactionContext::client_public_key]
48    pub async fn client_public_key(
49        &self,
50        ciphersuite: Ciphersuite,
51        credential_type: CredentialType,
52    ) -> CoreCryptoResult<Vec<u8>> {
53        Ok(self
54            .inner
55            .client_public_key(ciphersuite.into(), credential_type.into())
56            .await?)
57    }
58
59    /// See [core_crypto::mls::conversation::Conversation::epoch]
60    pub async fn conversation_epoch(&self, conversation_id: &ConversationId) -> CoreCryptoResult<u64> {
61        let conversation_id = conversation_id_vec!(conversation_id);
62        let conversation = self.inner.conversation(&conversation_id).await?;
63        Ok(conversation.epoch().await)
64    }
65
66    /// See [core_crypto::mls::conversation::Conversation::ciphersuite]
67    pub async fn conversation_ciphersuite(&self, conversation_id: &ConversationId) -> CoreCryptoResult<Ciphersuite> {
68        let conversation_id = conversation_id_vec!(conversation_id);
69        let cs = self.inner.conversation(&conversation_id).await?.ciphersuite().await;
70        Ok(Ciphersuite::from(core_crypto::prelude::CiphersuiteName::from(cs)))
71    }
72
73    /// See [core_crypto::prelude::Session::conversation_exists]
74    pub async fn conversation_exists(&self, conversation_id: &ConversationId) -> CoreCryptoResult<bool> {
75        let conversation_id = conversation_id_vec!(conversation_id);
76        self.inner
77            .conversation_exists(&conversation_id)
78            .await
79            .map_err(Into::into)
80    }
81
82    /// See [core_crypto::mls::conversation::Conversation::get_client_ids]
83    pub async fn get_client_ids(&self, conversation_id: &ConversationId) -> CoreCryptoResult<Vec<ClientId>> {
84        let conversation_id = conversation_id_vec!(conversation_id);
85        let conversation = self.inner.conversation(&conversation_id).await?;
86        let client_ids = conversation.get_client_ids().await.into_iter().map(ClientId).collect();
87        Ok(client_ids)
88    }
89
90    /// See [core_crypto::mls::conversation::Conversation::export_secret_key]
91    pub async fn export_secret_key(
92        &self,
93        conversation_id: &ConversationId,
94        key_length: u32,
95    ) -> CoreCryptoResult<Vec<u8>> {
96        let conversation_id = conversation_id_vec!(conversation_id);
97        let conversation = self.inner.conversation(&conversation_id).await?;
98        conversation
99            .export_secret_key(key_length as usize)
100            .await
101            .map_err(Into::into)
102    }
103
104    /// See [core_crypto::mls::conversation::Conversation::get_external_sender]
105    pub async fn get_external_sender(&self, conversation_id: &ConversationId) -> CoreCryptoResult<Vec<u8>> {
106        let conversation_id = conversation_id_vec!(conversation_id);
107        let conversation = self.inner.conversation(&conversation_id).await?;
108        conversation.get_external_sender().await.map_err(Into::into)
109    }
110
111    /// See [core_crypto::transaction_context::TransactionContext::get_or_create_client_keypackages]
112    pub async fn client_keypackages(
113        &self,
114        ciphersuite: Ciphersuite,
115        credential_type: CredentialType,
116        amount_requested: u32,
117    ) -> CoreCryptoResult<KeyPackages> {
118        let kps = self
119            .inner
120            .get_or_create_client_keypackages(ciphersuite.into(), credential_type.into(), amount_requested as usize)
121            .await
122            .map_err(RecursiveError::transaction("getting or creating client keypackages"))?;
123
124        kps.into_iter()
125            .map(|kp| {
126                kp.tls_serialize_detached()
127                    .map_err(core_crypto::mls::conversation::Error::tls_serialize("keypackage"))
128                    .map_err(RecursiveError::mls_conversation("serializing keypackage"))
129                    .map_err(Into::into)
130            })
131            .collect::<CoreCryptoResult<KeyPackages>>()
132    }
133
134    /// See [core_crypto::transaction_context::TransactionContext::client_valid_key_packages_count]
135    pub async fn client_valid_keypackages_count(
136        &self,
137        ciphersuite: Ciphersuite,
138        credential_type: CredentialType,
139    ) -> CoreCryptoResult<u64> {
140        let count = self
141            .inner
142            .client_valid_key_packages_count(ciphersuite.into(), credential_type.into())
143            .await
144            .map_err(RecursiveError::transaction("counting client valid keypackages"))?;
145
146        Ok(count.try_into().unwrap_or(0))
147    }
148
149    /// See [core_crypto::transaction_context::TransactionContext::delete_keypackages]
150    pub async fn delete_keypackages(&self, refs: KeyPackages) -> CoreCryptoResult<()> {
151        #[cfg(target_family = "wasm")]
152        let refs = refs.into_inner();
153        let refs = refs
154            .into_iter()
155            .map(|r| KeyPackageRef::from_slice(&r))
156            .collect::<Vec<_>>();
157
158        self.inner
159            .delete_keypackages(&refs[..])
160            .await
161            .map_err(RecursiveError::transaction("deleting keypackages"))?;
162        Ok(())
163    }
164
165    /// See [core_crypto::transaction_context::TransactionContext::new_conversation]
166    pub async fn create_conversation(
167        &self,
168        conversation_id: &ConversationId,
169        creator_credential_type: CredentialType,
170        config: ConversationConfiguration,
171    ) -> CoreCryptoResult<()> {
172        let conversation_id = conversation_id_vec!(conversation_id);
173
174        let mut lower_cfg = MlsConversationConfiguration {
175            custom: config.custom.into(),
176            ciphersuite: config.ciphersuite.map(Into::into).unwrap_or_default(),
177            ..Default::default()
178        };
179
180        self.inner
181            .set_raw_external_senders(&mut lower_cfg, config.external_senders)
182            .await?;
183
184        self.inner
185            .new_conversation(&conversation_id, creator_credential_type.into(), lower_cfg)
186            .await?;
187        Ok(())
188    }
189
190    /// See [core_crypto::transaction_context::TransactionContext::process_raw_welcome_message]
191    pub async fn process_welcome_message(
192        &self,
193        welcome_message: Vec<u8>,
194        custom_configuration: CustomConfiguration,
195    ) -> CoreCryptoResult<WelcomeBundle> {
196        let result = self
197            .inner
198            .process_raw_welcome_message(welcome_message, custom_configuration.into())
199            .await?
200            .into();
201        Ok(result)
202    }
203
204    /// See [core_crypto::mls::conversation::ConversationGuard::add_members]
205    pub async fn add_clients_to_conversation(
206        &self,
207        conversation_id: &ConversationId,
208        key_packages: KeyPackages,
209    ) -> CoreCryptoResult<NewCrlDistributionPoints> {
210        let conversation_id = conversation_id_vec!(conversation_id);
211
212        #[cfg(target_family = "wasm")]
213        let key_packages = key_packages.into_inner();
214        let key_packages = key_packages
215            .into_iter()
216            .map(|kp| {
217                KeyPackageIn::tls_deserialize(&mut kp.as_slice())
218                    .map_err(core_crypto::mls::conversation::Error::tls_deserialize("keypackage"))
219                    .map_err(RecursiveError::mls_conversation("adding members to conversation"))
220                    .map_err(Into::into)
221            })
222            .collect::<CoreCryptoResult<Vec<_>>>()?;
223
224        let mut conversation = self.inner.conversation(&conversation_id).await?;
225        let distribution_points: Option<Vec<_>> = conversation.add_members(key_packages).await?.into();
226        Ok(distribution_points.into())
227    }
228
229    /// See [core_crypto::mls::conversation::ConversationGuard::remove_members]
230    pub async fn remove_clients_from_conversation(
231        &self,
232        conversation_id: &ConversationId,
233        clients: Vec<ClientId>,
234    ) -> CoreCryptoResult<()> {
235        let clients: Vec<core_crypto::prelude::ClientId> = clients.into_iter().map(|c| c.0).collect();
236        let conversation_id = conversation_id_vec!(conversation_id);
237        let mut conversation = self.inner.conversation(&conversation_id).await?;
238        conversation.remove_members(&clients).await.map_err(Into::into)
239    }
240
241    /// See [core_crypto::mls::conversation::ConversationGuard::mark_as_child_of]
242    pub async fn mark_conversation_as_child_of(
243        &self,
244        child_id: &ConversationId,
245        parent_id: &ConversationId,
246    ) -> CoreCryptoResult<()> {
247        let parent_id = conversation_id_vec!(parent_id);
248        let child_id = conversation_id_vec!(child_id);
249        let mut conversation = self.inner.conversation(&child_id).await?;
250        conversation.mark_as_child_of(&parent_id).await.map_err(Into::into)
251    }
252
253    /// See [core_crypto::mls::conversation::ConversationGuard::update_key_material]
254    pub async fn update_keying_material(&self, conversation_id: &ConversationId) -> CoreCryptoResult<()> {
255        let conversation_id = conversation_id_vec!(conversation_id);
256        let mut conversation = self.inner.conversation(&conversation_id).await?;
257        conversation.update_key_material().await.map_err(Into::into)
258    }
259
260    /// See [core_crypto::mls::conversation::ConversationGuard::commit_pending_proposals]
261    pub async fn commit_pending_proposals(&self, conversation_id: &ConversationId) -> CoreCryptoResult<()> {
262        let conversation_id = conversation_id_vec!(conversation_id);
263        let mut conversation = self.inner.conversation(&conversation_id).await?;
264        conversation.commit_pending_proposals().await.map_err(Into::into)
265    }
266
267    /// See [core_crypto::mls::conversation::ConversationGuard::wipe]
268    pub async fn wipe_conversation(&self, conversation_id: &ConversationId) -> CoreCryptoResult<()> {
269        let conversation_id = conversation_id_vec!(conversation_id);
270        let mut conversation = self.inner.conversation(&conversation_id).await?;
271        conversation.wipe().await.map_err(Into::into)
272    }
273
274    /// See [core_crypto::mls::conversation::ConversationGuard::decrypt_message]
275    pub async fn decrypt_message(
276        &self,
277        conversation_id: &ConversationId,
278        payload: Vec<u8>,
279    ) -> CoreCryptoResult<DecryptedMessage> {
280        let conversation_id = conversation_id_vec!(conversation_id);
281        let conversation_result = self.inner.conversation(&conversation_id).await;
282        let decrypted_message = match conversation_result {
283            Err(TransactionError::PendingConversation(mut pending)) => {
284                pending.try_process_own_join_commit(&payload).await?
285            }
286            Ok(mut conversation) => conversation.decrypt_message(&payload).await?,
287            Err(e) => Err(e)?,
288        };
289
290        decrypted_message.try_into()
291    }
292
293    /// See [core_crypto::mls::conversation::ConversationGuard::encrypt_message]
294    pub async fn encrypt_message(
295        &self,
296        conversation_id: &ConversationId,
297        message: Vec<u8>,
298    ) -> CoreCryptoResult<Vec<u8>> {
299        let conversation_id = conversation_id_vec!(conversation_id);
300        let mut conversation = self.inner.conversation(&conversation_id).await?;
301        conversation.encrypt_message(message).await.map_err(Into::into)
302    }
303
304    /// See [core_crypto::transaction_context::TransactionContext::join_by_external_commit]
305    pub async fn join_by_external_commit(
306        &self,
307        group_info: Vec<u8>,
308        custom_configuration: CustomConfiguration,
309        credential_type: CredentialType,
310    ) -> CoreCryptoResult<WelcomeBundle> {
311        let group_info = VerifiableGroupInfo::tls_deserialize(&mut group_info.as_slice())
312            .map_err(core_crypto::mls::conversation::Error::tls_deserialize(
313                "verifiable group info",
314            ))
315            .map_err(RecursiveError::mls_conversation("joining by external commmit"))?;
316        let welcome_bundle = self
317            .inner
318            .join_by_external_commit(group_info, custom_configuration.into(), credential_type.into())
319            .await?;
320        Ok(welcome_bundle.into())
321    }
322}