core_crypto_ffi/core_crypto_context/
mls.rs1use 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 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 pub async fn mls_generate_keypairs(&self, ciphersuites: Ciphersuites) -> CoreCryptoResult<Vec<ClientId>> {
49 Ok(self
50 .inner
51 .mls_generate_keypairs((&ciphersuites).into())
52 .await
53 .map(|cids| cids.into_iter().map(ClientId).collect())?)
54 }
55
56 pub async fn mls_init_with_client_id(
58 &self,
59 client_id: ClientId,
60 tmp_client_ids: Vec<ClientId>,
61 ciphersuites: Ciphersuites,
62 ) -> CoreCryptoResult<()> {
63 Ok(self
64 .inner
65 .mls_init_with_client_id(
66 client_id.0,
67 tmp_client_ids.into_iter().map(|cid| cid.0).collect(),
68 (&ciphersuites).into(),
69 )
70 .await?)
71 }
72
73 pub async fn client_public_key(
75 &self,
76 ciphersuite: Ciphersuite,
77 credential_type: CredentialType,
78 ) -> CoreCryptoResult<Vec<u8>> {
79 Ok(self
80 .inner
81 .client_public_key(ciphersuite.into(), credential_type.into())
82 .await?)
83 }
84
85 pub async fn conversation_epoch(&self, conversation_id: &ConversationId) -> CoreCryptoResult<u64> {
87 let conversation_id = conversation_id_vec!(conversation_id);
88 let conversation = self.inner.conversation(&conversation_id).await?;
89 Ok(conversation.epoch().await)
90 }
91
92 pub async fn conversation_ciphersuite(&self, conversation_id: &ConversationId) -> CoreCryptoResult<Ciphersuite> {
94 let conversation_id = conversation_id_vec!(conversation_id);
95 let cs = self.inner.conversation(&conversation_id).await?.ciphersuite().await;
96 Ok(Ciphersuite::from(core_crypto::prelude::CiphersuiteName::from(cs)))
97 }
98
99 pub async fn conversation_exists(&self, conversation_id: &ConversationId) -> CoreCryptoResult<bool> {
101 let conversation_id = conversation_id_vec!(conversation_id);
102 self.inner
103 .conversation_exists(&conversation_id)
104 .await
105 .map_err(Into::into)
106 }
107
108 pub async fn get_client_ids(&self, conversation_id: &ConversationId) -> CoreCryptoResult<Vec<ClientId>> {
110 let conversation_id = conversation_id_vec!(conversation_id);
111 let conversation = self.inner.conversation(&conversation_id).await?;
112 let client_ids = conversation.get_client_ids().await.into_iter().map(ClientId).collect();
113 Ok(client_ids)
114 }
115
116 pub async fn export_secret_key(
118 &self,
119 conversation_id: &ConversationId,
120 key_length: u32,
121 ) -> CoreCryptoResult<Vec<u8>> {
122 let conversation_id = conversation_id_vec!(conversation_id);
123 let conversation = self.inner.conversation(&conversation_id).await?;
124 conversation
125 .export_secret_key(key_length as usize)
126 .await
127 .map_err(Into::into)
128 }
129
130 pub async fn get_external_sender(&self, conversation_id: &ConversationId) -> CoreCryptoResult<Vec<u8>> {
132 let conversation_id = conversation_id_vec!(conversation_id);
133 let conversation = self.inner.conversation(&conversation_id).await?;
134 conversation.get_external_sender().await.map_err(Into::into)
135 }
136
137 pub async fn client_keypackages(
139 &self,
140 ciphersuite: Ciphersuite,
141 credential_type: CredentialType,
142 amount_requested: u32,
143 ) -> CoreCryptoResult<KeyPackages> {
144 let kps = self
145 .inner
146 .get_or_create_client_keypackages(ciphersuite.into(), credential_type.into(), amount_requested as usize)
147 .await
148 .map_err(RecursiveError::mls_client("getting or creating client keypackages"))?;
149
150 kps.into_iter()
151 .map(|kp| {
152 kp.tls_serialize_detached()
153 .map_err(core_crypto::mls::conversation::Error::tls_serialize("keypackage"))
154 .map_err(RecursiveError::mls_conversation("serializing keypackage"))
155 .map_err(Into::into)
156 })
157 .collect::<CoreCryptoResult<KeyPackages>>()
158 }
159
160 pub async fn client_valid_keypackages_count(
162 &self,
163 ciphersuite: Ciphersuite,
164 credential_type: CredentialType,
165 ) -> CoreCryptoResult<u64> {
166 let count = self
167 .inner
168 .client_valid_key_packages_count(ciphersuite.into(), credential_type.into())
169 .await
170 .map_err(RecursiveError::mls_client("counting client valid keypackages"))?;
171
172 Ok(count.try_into().unwrap_or(0))
173 }
174
175 pub async fn delete_keypackages(&self, refs: KeyPackages) -> CoreCryptoResult<()> {
177 #[cfg(target_family = "wasm")]
178 let refs = refs.into_inner();
179 let refs = refs
180 .into_iter()
181 .map(|r| KeyPackageRef::from_slice(&r))
182 .collect::<Vec<_>>();
183
184 self.inner
185 .delete_keypackages(&refs[..])
186 .await
187 .map_err(RecursiveError::mls_client("deleting keypackages"))?;
188 Ok(())
189 }
190
191 pub async fn create_conversation(
193 &self,
194 conversation_id: &ConversationId,
195 creator_credential_type: CredentialType,
196 config: ConversationConfiguration,
197 ) -> CoreCryptoResult<()> {
198 let conversation_id = conversation_id_vec!(conversation_id);
199
200 let mut lower_cfg = MlsConversationConfiguration {
201 custom: config.custom.into(),
202 ciphersuite: config.ciphersuite.map(Into::into).unwrap_or_default(),
203 ..Default::default()
204 };
205
206 self.inner
207 .set_raw_external_senders(&mut lower_cfg, config.external_senders)
208 .await?;
209
210 self.inner
211 .new_conversation(&conversation_id, creator_credential_type.into(), lower_cfg)
212 .await?;
213 Ok(())
214 }
215
216 pub async fn process_welcome_message(
218 &self,
219 welcome_message: Vec<u8>,
220 custom_configuration: CustomConfiguration,
221 ) -> CoreCryptoResult<WelcomeBundle> {
222 let result = self
223 .inner
224 .process_raw_welcome_message(welcome_message, custom_configuration.into())
225 .await?
226 .into();
227 Ok(result)
228 }
229
230 pub async fn add_clients_to_conversation(
232 &self,
233 conversation_id: &ConversationId,
234 key_packages: KeyPackages,
235 ) -> CoreCryptoResult<NewCrlDistributionPoints> {
236 let conversation_id = conversation_id_vec!(conversation_id);
237
238 #[cfg(target_family = "wasm")]
239 let key_packages = key_packages.into_inner();
240 let key_packages = key_packages
241 .into_iter()
242 .map(|kp| {
243 KeyPackageIn::tls_deserialize(&mut kp.as_slice())
244 .map_err(core_crypto::mls::conversation::Error::tls_deserialize("keypackage"))
245 .map_err(RecursiveError::mls_conversation("adding members to conversation"))
246 .map_err(Into::into)
247 })
248 .collect::<CoreCryptoResult<Vec<_>>>()?;
249
250 let mut conversation = self.inner.conversation(&conversation_id).await?;
251 let distribution_points: Option<Vec<_>> = conversation.add_members(key_packages).await?.into();
252 Ok(distribution_points.into())
253 }
254
255 pub async fn remove_clients_from_conversation(
257 &self,
258 conversation_id: &ConversationId,
259 clients: Vec<ClientId>,
260 ) -> CoreCryptoResult<()> {
261 let clients: Vec<core_crypto::prelude::ClientId> = clients.into_iter().map(|c| c.0).collect();
262 let conversation_id = conversation_id_vec!(conversation_id);
263 let mut conversation = self.inner.conversation(&conversation_id).await?;
264 conversation.remove_members(&clients).await.map_err(Into::into)
265 }
266
267 pub async fn mark_conversation_as_child_of(
269 &self,
270 child_id: &ConversationId,
271 parent_id: &ConversationId,
272 ) -> CoreCryptoResult<()> {
273 let parent_id = conversation_id_vec!(parent_id);
274 let child_id = conversation_id_vec!(child_id);
275 let mut conversation = self.inner.conversation(&child_id).await?;
276 conversation.mark_as_child_of(&parent_id).await.map_err(Into::into)
277 }
278
279 pub async fn update_keying_material(&self, conversation_id: &ConversationId) -> CoreCryptoResult<()> {
281 let conversation_id = conversation_id_vec!(conversation_id);
282 let mut conversation = self.inner.conversation(&conversation_id).await?;
283 conversation.update_key_material().await.map_err(Into::into)
284 }
285
286 pub async fn commit_pending_proposals(&self, conversation_id: &ConversationId) -> CoreCryptoResult<()> {
288 let conversation_id = conversation_id_vec!(conversation_id);
289 let mut conversation = self.inner.conversation(&conversation_id).await?;
290 conversation.commit_pending_proposals().await.map_err(Into::into)
291 }
292
293 pub async fn wipe_conversation(&self, conversation_id: &ConversationId) -> CoreCryptoResult<()> {
295 let conversation_id = conversation_id_vec!(conversation_id);
296 let mut conversation = self.inner.conversation(&conversation_id).await?;
297 conversation.wipe().await.map_err(Into::into)
298 }
299
300 pub async fn decrypt_message(
302 &self,
303 conversation_id: &ConversationId,
304 payload: Vec<u8>,
305 ) -> CoreCryptoResult<DecryptedMessage> {
306 let conversation_id = conversation_id_vec!(conversation_id);
307 let conversation_result = self.inner.conversation(&conversation_id).await;
308 let decrypted_message = match conversation_result {
309 Err(TransactionError::PendingConversation(mut pending)) => {
310 pending.try_process_own_join_commit(&payload).await?
311 }
312 Ok(mut conversation) => conversation.decrypt_message(&payload).await?,
313 Err(e) => Err(e)?,
314 };
315
316 decrypted_message.try_into()
317 }
318
319 pub async fn encrypt_message(
321 &self,
322 conversation_id: &ConversationId,
323 message: Vec<u8>,
324 ) -> CoreCryptoResult<Vec<u8>> {
325 let conversation_id = conversation_id_vec!(conversation_id);
326 let mut conversation = self.inner.conversation(&conversation_id).await?;
327 conversation.encrypt_message(message).await.map_err(Into::into)
328 }
329
330 pub async fn join_by_external_commit(
332 &self,
333 group_info: Vec<u8>,
334 custom_configuration: CustomConfiguration,
335 credential_type: CredentialType,
336 ) -> CoreCryptoResult<WelcomeBundle> {
337 let group_info = VerifiableGroupInfo::tls_deserialize(&mut group_info.as_slice())
338 .map_err(core_crypto::mls::conversation::Error::tls_deserialize(
339 "verifiable group info",
340 ))
341 .map_err(RecursiveError::mls_conversation("joining by external commmit"))?;
342 let welcome_bundle = self
343 .inner
344 .join_by_external_commit(group_info, custom_configuration.into(), credential_type.into())
345 .await?;
346 Ok(welcome_bundle.into())
347 }
348}