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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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}