core_crypto_ffi/core_crypto_context/
e2ei.rs

1use crate::{
2    Ciphersuite, ClientId, ConversationId, CoreCryptoContext, CoreCryptoError, CoreCryptoResult, CredentialType,
3    CrlRegistration, E2eiConversationState, E2eiDumpedPkiEnv, E2eiEnrollment, NewCrlDistributionPoints, UserIdentities,
4    WireIdentity, conversation_id_vec,
5};
6use core_crypto::transaction_context::Error as TransactionError;
7use core_crypto::{RecursiveError, mls::conversation::Conversation as _, prelude::VerifiableGroupInfo};
8use std::collections::HashMap;
9#[cfg(not(target_family = "wasm"))]
10use std::sync::Arc;
11use tls_codec::Deserialize as _;
12#[cfg(target_family = "wasm")]
13use wasm_bindgen::prelude::*;
14
15#[cfg(not(target_family = "wasm"))]
16type EnrollmentParameter = Arc<E2eiEnrollment>;
17
18#[cfg(target_family = "wasm")]
19type EnrollmentParameter = E2eiEnrollment;
20
21#[cfg_attr(target_family = "wasm", wasm_bindgen)]
22#[cfg_attr(not(target_family = "wasm"), uniffi::export)]
23impl CoreCryptoContext {
24    /// See [core_crypto::transaction_context::TransactionContext::e2ei_new_enrollment]
25    pub async fn e2ei_new_enrollment(
26        &self,
27        client_id: String,
28        display_name: String,
29        handle: String,
30        team: Option<String>,
31        expiry_sec: u32,
32        ciphersuite: Ciphersuite,
33    ) -> CoreCryptoResult<E2eiEnrollment> {
34        self.inner
35            .e2ei_new_enrollment(
36                client_id.into_bytes().into(),
37                display_name,
38                handle,
39                team,
40                expiry_sec,
41                ciphersuite.into(),
42            )
43            .await
44            .map(E2eiEnrollment::new)
45            .map_err(Into::<TransactionError>::into)
46            .map_err(Into::into)
47    }
48
49    /// See [core_crypto::transaction_context::TransactionContext::e2ei_new_activation_enrollment]
50    pub async fn e2ei_new_activation_enrollment(
51        &self,
52        display_name: String,
53        handle: String,
54        team: Option<String>,
55        expiry_sec: u32,
56        ciphersuite: Ciphersuite,
57    ) -> CoreCryptoResult<E2eiEnrollment> {
58        self.inner
59            .e2ei_new_activation_enrollment(display_name, handle, team, expiry_sec, ciphersuite.into())
60            .await
61            .map(E2eiEnrollment::new)
62            .map_err(Into::<TransactionError>::into)
63            .map_err(Into::into)
64    }
65
66    /// See [core_crypto::transaction_context::TransactionContext::e2ei_new_rotate_enrollment]
67    pub async fn e2ei_new_rotate_enrollment(
68        &self,
69        display_name: Option<String>,
70        handle: Option<String>,
71        team: Option<String>,
72        expiry_sec: u32,
73        ciphersuite: Ciphersuite,
74    ) -> CoreCryptoResult<E2eiEnrollment> {
75        self.inner
76            .e2ei_new_rotate_enrollment(display_name, handle, team, expiry_sec, ciphersuite.into())
77            .await
78            .map(E2eiEnrollment::new)
79            .map_err(Into::<TransactionError>::into)
80            .map_err(Into::into)
81    }
82
83    /// See [core_crypto::transaction_context::TransactionContext::e2ei_register_acme_ca]
84    pub async fn e2ei_register_acme_ca(&self, trust_anchor_pem: String) -> CoreCryptoResult<()> {
85        self.inner
86            .e2ei_register_acme_ca(trust_anchor_pem)
87            .await
88            .map_err(Into::<TransactionError>::into)
89            .map_err(Into::into)
90    }
91
92    /// See [core_crypto::transaction_context::TransactionContext::e2ei_register_intermediate_ca_pem]
93    pub async fn e2ei_register_intermediate_ca(&self, cert_pem: String) -> CoreCryptoResult<NewCrlDistributionPoints> {
94        self.inner
95            .e2ei_register_intermediate_ca_pem(cert_pem)
96            .await
97            .map(Into::into)
98            .map_err(Into::<TransactionError>::into)
99            .map_err(Into::into)
100    }
101
102    /// See [core_crypto::transaction_context::TransactionContext::e2ei_register_crl]
103    pub async fn e2ei_register_crl(&self, crl_dp: String, crl_der: Vec<u8>) -> CoreCryptoResult<CrlRegistration> {
104        self.inner
105            .e2ei_register_crl(crl_dp, crl_der)
106            .await
107            .map(Into::into)
108            .map_err(Into::<TransactionError>::into)
109            .map_err(Into::into)
110    }
111
112    /// See [core_crypto::transaction_context::TransactionContext::e2ei_mls_init_only]
113    pub async fn e2ei_mls_init_only(
114        &self,
115        enrollment: EnrollmentParameter,
116        certificate_chain: String,
117        nb_key_package: Option<u32>,
118    ) -> CoreCryptoResult<NewCrlDistributionPoints> {
119        let nb_key_package = nb_key_package
120            .map(usize::try_from)
121            .transpose()
122            .map_err(CoreCryptoError::generic())?;
123        let mut enrollment = enrollment.write().await;
124        self.inner
125            .e2ei_mls_init_only(&mut enrollment, certificate_chain, nb_key_package)
126            .await
127            .map(Into::into)
128            .map_err(Into::<TransactionError>::into)
129            .map_err(Into::into)
130    }
131
132    /// See [core_crypto::mls::conversation::ConversationGuard::e2ei_rotate]
133    pub async fn e2ei_rotate(&self, conversation_id: &ConversationId) -> CoreCryptoResult<()> {
134        let conversation_id = conversation_id_vec!(conversation_id);
135        let mut conversation = self.inner.conversation(&conversation_id).await?;
136        conversation.e2ei_rotate(None).await.map_err(Into::into)
137    }
138
139    /// See [core_crypto::transaction_context::TransactionContext::save_x509_credential]
140    pub async fn save_x509_credential(
141        &self,
142        enrollment: EnrollmentParameter,
143        certificate_chain: String,
144    ) -> CoreCryptoResult<NewCrlDistributionPoints> {
145        let mut enrollment = enrollment.write().await;
146        self.inner
147            .save_x509_credential(&mut enrollment, certificate_chain)
148            .await
149            .map(Into::into)
150            .map_err(Into::<TransactionError>::into)
151            .map_err(Into::into)
152    }
153
154    /// See [core_crypto::transaction_context::TransactionContext::delete_stale_key_packages]
155    pub async fn delete_stale_key_packages(&self, ciphersuite: Ciphersuite) -> CoreCryptoResult<()> {
156        self.inner
157            .delete_stale_key_packages(ciphersuite.into())
158            .await
159            .map_err(Into::<TransactionError>::into)
160            .map_err(Into::into)
161    }
162
163    /// See [core_crypto::transaction_context::TransactionContext::e2ei_enrollment_stash]
164    ///
165    /// Note that this can only succeed id the enrollment is unique and there are no other hard refs to it.
166    pub async fn e2ei_enrollment_stash(&self, enrollment: EnrollmentParameter) -> CoreCryptoResult<Vec<u8>> {
167        #[cfg(not(target_family = "wasm"))]
168        let enrollment = Arc::into_inner(enrollment).ok_or_else(|| {
169            CoreCryptoError::ad_hoc("outer enrollment had multiple strong refs and could not be unpacked")
170        })?;
171        let enrollment = enrollment.into_inner().ok_or_else(|| {
172            CoreCryptoError::ad_hoc("inner enrollment had multiple strong refs and could not be unpacked")
173        })?;
174
175        self.inner
176            .e2ei_enrollment_stash(enrollment)
177            .await
178            .map_err(Into::<TransactionError>::into)
179            .map_err(Into::into)
180    }
181
182    /// See [core_crypto::transaction_context::TransactionContext::e2ei_enrollment_stash_pop]
183    pub async fn e2ei_enrollment_stash_pop(&self, handle: Vec<u8>) -> CoreCryptoResult<E2eiEnrollment> {
184        self.inner
185            .e2ei_enrollment_stash_pop(handle)
186            .await
187            .map(E2eiEnrollment::new)
188            .map_err(Into::<TransactionError>::into)
189            .map_err(Into::into)
190    }
191
192    /// See [core_crypto::mls::conversation::conversation_guard::ConversationGuard::e2ei_conversation_state]
193    pub async fn e2ei_conversation_state(
194        &self,
195        conversation_id: &ConversationId,
196    ) -> CoreCryptoResult<E2eiConversationState> {
197        let conversation_id = conversation_id_vec!(conversation_id);
198        let conversation = self.inner.conversation(&conversation_id).await?;
199        conversation
200            .e2ei_conversation_state()
201            .await
202            .map(Into::into)
203            .map_err(Into::into)
204    }
205
206    /// See [core_crypto::mls::Client::e2ei_is_enabled]
207    pub async fn e2ei_is_enabled(&self, ciphersuite: Ciphersuite) -> CoreCryptoResult<bool> {
208        let sc = core_crypto::prelude::MlsCiphersuite::from(core_crypto::prelude::CiphersuiteName::from(ciphersuite))
209            .signature_algorithm();
210        self.inner
211            .e2ei_is_enabled(sc)
212            .await
213            .map_err(Into::<TransactionError>::into)
214            .map_err(Into::into)
215    }
216
217    /// See [core_crypto::mls::Client::get_device_identities]
218    pub async fn get_device_identities(
219        &self,
220        conversation_id: &ConversationId,
221        device_ids: Vec<ClientId>,
222    ) -> CoreCryptoResult<Vec<WireIdentity>> {
223        let device_ids = device_ids.into_iter().map(|cid| cid.0).collect::<Vec<_>>();
224        let conversation_id = conversation_id_vec!(conversation_id);
225        let conversation = self.inner.conversation(&conversation_id).await?;
226        let wire_ids = conversation.get_device_identities(device_ids.as_slice()).await?;
227        Ok(wire_ids.into_iter().map(Into::into).collect())
228    }
229
230    /// See [core_crypto::mls::Client::get_user_identities]
231    #[cfg_attr(
232        target_family = "wasm",
233        wasm_bindgen(unchecked_return_type = "Map<string, WireIdentity[]>")
234    )]
235    pub async fn get_user_identities(
236        &self,
237        conversation_id: &ConversationId,
238        user_ids: Vec<String>,
239    ) -> CoreCryptoResult<UserIdentities> {
240        let conversation_id = conversation_id_vec!(conversation_id);
241        let conversation = self.inner.conversation(&conversation_id).await?;
242        let user_ids = conversation.get_user_identities(user_ids.as_slice()).await?;
243        let user_ids = user_ids
244            .into_iter()
245            .map(|(k, v)| (k, v.into_iter().map(WireIdentity::from).collect()))
246            .collect::<HashMap<_, Vec<_>>>();
247        #[cfg(target_family = "wasm")]
248        let user_ids = serde_wasm_bindgen::to_value(&user_ids)?;
249        Ok(user_ids)
250    }
251
252    /// See [core_crypto::mls::Client::get_credential_in_use]
253    pub async fn get_credential_in_use(
254        &self,
255        group_info: Vec<u8>,
256        credential_type: CredentialType,
257    ) -> CoreCryptoResult<E2eiConversationState> {
258        let group_info = VerifiableGroupInfo::tls_deserialize(&mut group_info.as_slice())
259            .map_err(core_crypto::mls::conversation::Error::tls_deserialize(
260                "verifiable group info",
261            ))
262            .map_err(RecursiveError::mls_conversation("getting credential in use"))?;
263        self.inner
264            .get_credential_in_use(group_info, credential_type.into())
265            .await
266            .map(Into::into)
267            .map_err(Into::<TransactionError>::into)
268            .map_err(Into::into)
269    }
270
271    pub async fn e2ei_dump_pki_env(&self) -> CoreCryptoResult<Option<E2eiDumpedPkiEnv>> {
272        self.inner
273            .e2ei_dump_pki_env()
274            .await
275            .map(|option| option.map(Into::into))
276            .map_err(Into::<TransactionError>::into)
277            .map_err(Into::into)
278    }
279
280    /// See [core_crypto::mls::MlsCentral::e2ei_is_pki_env_setup]
281    pub async fn e2ei_is_pki_env_setup(&self) -> CoreCryptoResult<bool> {
282        self.inner
283            .e2ei_is_pki_env_setup()
284            .await
285            .map_err(Into::<TransactionError>::into)
286            .map_err(Into::into)
287    }
288}